home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / qpClass < prev    next >
Text File  |  1998-12-18  |  81KB  |  3,087 lines

  1. ppc?
  2. [IF]
  3.  
  4. forward  (meth_in_mod)        \ calls a method in a module when the module
  5.                             \  is already loaded and we know its base
  6.                             \  addr - see zModules.
  7.  
  8. forward  register_check
  9.  
  10. \ forward ?enterHeldMod        \ If an object's class is in a module, heldMod
  11.                             \  will be nonzero straight after we resolve the class
  12.                             \  pointer.  Even if we eventually bind to a method that's
  13.                             \  not in the module, it turns out we need the module's
  14.                             \  base registers set up since we might call other methods
  15.                             \  that are in the module, via linked objects.
  16.  
  17. \ :f ?enterHeldMod  ;f        \ need to give it an initial dummy definition
  18.                             \  'cause it gets called before zModules is
  19.                             \  loaded.
  20.  
  21. 0    value    prev_link        \ saves prev link to current method - in
  22.                             \  68k mode, it's in cg5 which gets
  23.                             \  loaded first
  24.  
  25. [THEN]
  26.  
  27.  
  28. PPC? not
  29. [IF]
  30. ' pfind  -> ufind            \ in case of error - we set it to 1stFind
  31.                             \  once we define it below
  32. [THEN]
  33.  
  34.  
  35. \ For all the class/object formats, see cg1.
  36.  
  37.  
  38.  
  39.     12    constant    obj_hdr_length        \ was 8 on 68k
  40.  
  41. false    value        68k_align?            \ used in implementing 68k_record, so we
  42.                                         \  can handle 68k-format Toolbox records
  43.  
  44.  
  45. PPC?
  46. [IF]        \ We have to define all the values etc. that are defined in Class
  47.             \  on the 68k.
  48.  
  49.     20    constant    static_ivar_offs
  50.                             \ the offset from the start of the ivar dic
  51.                             \  info for a static ivar, to the ivar's data.
  52.                             \  The ivar info is 18 bytes long, then we have
  53.                             \  to align.
  54.  
  55.  
  56.     0    value    PUB/PRIV    \ -1 private, 1 public, 0 default - for ivars and methods
  57. false    value    STATIC?        \ true if following ivars are to be static
  58.     0    value    ^COMP_CLASS    \ addr of the class we're currently compiling
  59.     0    value    PIVAR        \ hashed name of any public ivar we're accessing
  60.     0    value    PIVSEL        \ hashed selector of any msg being sent to
  61.                             \  to a public ivar
  62.  
  63.     0    value    NEWOBJECT    \ addr of object being created
  64.     0    value    #SUP        \ number of superclasses for current class
  65.     0    value    SUPERS_TO_SKIP
  66.  
  67. false    value    REC?        \ Are we compiling a record?
  68. false    value    UNION?        \ Are we compiling a union in a record?
  69.     0    value    UNIONOFFS    \ Base offset of the current union
  70.     0    value    emb_obj_offs    \ used in inline binding - deliberately
  71.                                 \  a different name to emb_obj_offs
  72.                                 \  in qClass so we don't get confused
  73.  
  74. initID    constant    INITID
  75.  
  76.  
  77. : ILFA     ( infa -- ilfa )     inline{ 4+}  ;
  78.  
  79. : ^ICLASS  ( infa -- ^class | 0 )
  80.     8 + dup @ NIF   drop 0   ELSE   @abs ?>classInMod   THEN  ;
  81.  
  82. : IOFFS    ( infa -- ioffs )    inline{ 12 + w@}  ;
  83. : I#ELS    ( infa -- #els )    inline{ 14 + w@}  ;
  84. : IFFA     ( infa -- iffa )    inline{ 16 +}  ;
  85.  
  86. : ^NEXTIVAR    \ ( infa -- infa' )
  87.     ilfa  displace  ;
  88.  
  89. [THEN]
  90.  
  91.  
  92. : >OBJ        \ ( xt -- addr )  xt results from ticking an object, or the
  93.             \  equivalent (ticking an object isn't really legal).  Returns
  94.             \  the object's data address.  On the 68k this was just 8+,
  95.             \  but here we have to go from the code to the data area.
  96.     2+ @abs  ;
  97.  
  98. : OBJ>        \ ( addr -- xt | 0 )  takes an obj's base addr, and returns the
  99.             \  xt of its dic entry, or zero if none.
  100.     12 - dup @ IF  @abs  ELSE  drop 0  THEN  ;
  101.  
  102.  
  103. ppc? not
  104. [IF]            \ the PPC versions of these are in pnuc4
  105.  
  106. : CLASS?  ( xt -- xt b )
  107.     dup 2- w@
  108.     dup  $ BC1D = swap $ BC2D = or  ;    \ class_h or class_in_mod_h are OK
  109.  
  110.  
  111. : CHKCLASS    \ ( xt -- xt )
  112.     class?  ?EXIT
  113.     .id  space  80 die  ;
  114.  
  115.  
  116. : >classRP { ^obj \ ^class tmp -- ^classRP | -- 0 }
  117.  
  118. (*    Takes an object address and returns the address of the reloc pointer
  119.     to the class (which will be somewhere in front of the object's data).
  120.     Returns zero if the passed-in address isn't an object address.
  121.     Needs to work for heap as well as dictionary objects.  The test is very
  122.     unlikely (maybe 1/2**24) to indicate a non-object as being an object.
  123.     To save time we don't do a conservative check on ^obj actually being a 
  124.     legal address (unlike ALIGNED_ADDR?), apart from checking that it is aligned,
  125.     which is a very quick check.  This means we may crash if an aligned but 
  126.     illegal address is passed in.  The presumption is that it really is an 
  127.     object address, and that anything else is a comparatively unlikely error.
  128. *)
  129.     false                            \ guilty until proven innocent
  130.     ^obj 3 and              ?EXIT    \ if not aligned, it can't be an obj addr
  131.     ^obj -> theObj                    \ save obj addr in theObj - needed sometimes
  132.     ^obj 4 - w@x -> tmp                \ grab ^class offset
  133.     tmp 3 and                ?EXIT    \  which must be aligned
  134.     tmp $ FF00 and $ FF00 =    0EXIT    \  and must be $FFxx
  135.     ^obj 4 - ++> tmp                \ now tmp points to the reloc class ptr
  136.     drop  tmp                        \ which is what we return
  137. ;
  138.  
  139. : classRP>class  { ^classRP -- ^class | -- 0 }
  140.         \ Takes the address of a class reloc pointer, and returns the
  141.         \  real class address, going into a module if necessary.
  142.         \ Returns zero if the reloc pointer doesn't point to a class.
  143.  
  144.     ^classRP @abs  class?
  145.     NIF  drop 0  EXIT  THEN        \ if not a class, orig addr wasn't an obj addr
  146.     
  147. \    ?>classInMod        - no modules in target compilation
  148. ;
  149.  
  150.  
  151. : >CLASS  { ^obj \ ^class tmp -- ^class | -- 0 }
  152.  
  153. (*    Converts an object address to its class address, going into a module if
  154.     necessary.  Returns zero if the passed-in address isn't an object address.
  155.     For other comments, see >classRP.
  156. *)
  157.  
  158.     ^obj >classRP  dup  0EXIT        \ out with zero if not a legal object
  159.     classRP>class
  160. ;
  161.  
  162. [THEN]
  163.  
  164.  
  165. : ?>CLASS   ( ^obj -- ^class )
  166.     >class  dup NIF 81 die THEN  ;        \ If no legal class ptr, probably
  167.                                         \ not an obj addr at all!
  168.  
  169. : ?CLASS        \ Error if not compiling a class definition.
  170.     cstate NIF 115 die  THEN  ;
  171.  
  172.  
  173. PPC? not
  174. [IF]
  175.  
  176. (*    The following offsets refer to where a ^class points, i.e. the cfa
  177.     of the class.  They're a bit different on the PPC.  And here in
  178.     cg-class in 68k mode, I can't use inlines since I've already
  179.     redefined inline{ to compile PPC stuff, and it's immediate!
  180.  
  181.     In PPC mode, I'm defining these in pnuc4, since they're needed
  182.     by (findM) which comes there.
  183.  
  184.     MFA_offset picks one of the 8 method threads, given a selID.
  185.     The selID is probably not very random in the low byte (since
  186.     selectors all end in ":", so we hash it a little more then pick
  187.     the 3 bits from the result which are already in the right position.
  188.  
  189.     Note: it took a surprising amount of trial and error to get a
  190.     good extra hash for this particular use!
  191. *)
  192.  
  193. : MFA_offset  ( selID ^class -- selID ^class MFA_offset )
  194.     over
  195.     dup 5 >> +
  196.     $ 1C and  2 +  ;
  197.  
  198. \ 34    constant    IFA_offset    *** we can't use CONSTANT here in qClass!
  199.  
  200. : FFA    ;            \ Flags
  201.  
  202. : MFA  ( SelID ^Class -- SelID MFA )  MFA_offset  + ;
  203.  
  204. : IFA    34 +  ;            \ ivar link
  205. : DFA    40 +  ;            \ Data len (2 bytes),
  206.                         \  width of indexed elts (2 bytes)
  207. : XOFFA    44 +  ;            \ offset to ivar with indexing offset for
  208.                         \  large_obj_arrays
  209. : SFA    46 +  ;            \ Superclass N-way pointer
  210.  
  211. \ 46    constant    classSize        \ total size of class info up to N-way
  212.  
  213.  
  214. [THEN]
  215.  
  216.  
  217. : into_flags  { new_flags -- }
  218.     ?class  ^comp_class ffa dup w@  new_flags or  swap w!  ;
  219.  
  220. : CAN_BE_GPR        $ 30  into_flags  ;
  221. : CAN_BE_FPR        $ 40  into_flags  ;
  222. : CAN_BE_VR            $ 50  into_flags  ;
  223.  
  224. : ALIGNMENT  ( n -- )  8 << into_flags  ;        \ n is power of 2
  225.  
  226.  
  227. \ for our 68k compilation, there aren't any modules.  The real versions
  228. \  are in pnuc3.
  229.  
  230. PPC? not
  231. [IF]
  232.  
  233. : ?>classinMod  ;
  234. : ?unholdMod  ;
  235.  
  236. : xcan_be_gpr    can_be_gpr  ;
  237.  
  238. [THEN]
  239.  
  240.  
  241. : (^DLEN)    \ ( ^obj -- ^datalen )  This is a low-level word which should
  242.             \  normally only be used in the Mops system stuff.  Note it
  243.             \  takes ^obj, not ^class, and it doesn't do a module check
  244.             \  - it assumes the class is in the same segment as the object.
  245.     ?>class dfa  ;
  246.  
  247. : (DLEN&XWID)    ( ^class -- dlen xwid )    \ Assumes ^class is the true class
  248.         dfa dup  w@  swap  2+ w@  ;        \  address, not main dictionary address
  249.                                         \  of exported class in module
  250.                                         \ Only intended for internal use!
  251.  
  252. : DLEN&XWID        ( ^class -- dlen xwid )
  253.     ?>classInMod
  254.     (dlen&xwid)
  255.     ?unHoldMod  ;
  256.  
  257.  
  258. : DLEN    dlen&xwid  drop  ;
  259. : XWID    dlen&xwid  nip   ;
  260.  
  261.  
  262. PPC?
  263. [IF]
  264. : IVARLEN    inline{ dlen} ;                \ an alias for dlen
  265. [ELSE]
  266. : IVARLEN    dlen  ;
  267. [THEN]
  268.  
  269. : OBJLEN    \ ( -- objlen )  Computes total data length of current object.
  270.  
  271.     ^base (^dlen)  dup w@            \ ivar len
  272.     swap 2+ w@  ?dup
  273.     IF            \ we're indexed
  274.         swap  #off-align 6 +  swap    \ add len of indexed header
  275.         idxBase 4- @ 1+  * +        \ and len of indexed elements
  276.     THEN
  277. ;
  278.  
  279. PPC?
  280. [IF]
  281. : ?>MAINDIC  { ^class -- '^class }
  282.         \ If ^class is exported from a module, we return the main dic
  283.         \ equivalent.  If it's not exported, we return it unchanged.
  284.         \ We need this word since for exported classes, we need to use the
  285.         \ imported address (in the main dictionary) as the class pointer
  286.         \ in a new object or an ivar dic entry (so that the module will be
  287.         \ invoked properly when a method is sent to the object.
  288.  
  289.     ^class ffa 1+ c@  2 and
  290.     IF        ^class >name n>count sfind drop
  291.     ELSE    ^class
  292.     THEN  ;
  293.  
  294. [THEN]
  295.  
  296.  
  297. : LARGE_OBJ_ARRAY_CHECK  { ^class offs \ xoffs  -- offs xdispl-offs }
  298.  
  299. \ Following <findM> or <IVfindM>, we check if this is a large_obj_array,
  300. \  in which case we might have to map the obj/ivar into the indexed area:
  301.  
  302.     ^class xoffa w@  -> xoffs    \ offs where remapping ends - are we before that?
  303.     ^class searchedClass <>
  304.     offs xoffs <  and
  305.     IF            \ yes - remapping necessary.  Return offs to xdispl ivar
  306.         offs  xoffs 12 +
  307.     ELSE        \ no - normal case - just return zero
  308.         offs 0
  309.     THEN
  310. ;
  311.  
  312.  
  313. : <findM>  { selID ^class \ xt offs  -- xt offs xdispl-offs }
  314.  
  315. (*    Factored out from clFindm and objFindm.  Finds a method's cfa given a
  316.     selID and a class address, *which has already been converted to a module
  317.     addr if necessary*.
  318.     
  319.     offs will be nonzero if the method turns out to belong to a superclass
  320.     with a non-zero offset in the object - i.e. an embedded object.
  321.     If it's a large_obj_array, and the object is in the indexed area,
  322.     xdispl-offs will be nonzero.  This allows the caller to compile
  323.     code to add the offset to the selected element.
  324. *)
  325.     ^class -> objClass                    \ used in error msgs and inline binding
  326.  
  327.     selID  ^class  MFA_offset  true  (findm)
  328.     NIF  cr  ^class .id  108 die        \ "method not found"
  329.     THEN
  330. [ ppc? not ]
  331. [if]
  332.     4+        \ (findm) on 68k returns 68k method cfa - on PPC the
  333.             \  equivalent is 4 bytes later - same as the xt of a
  334.             \  colon defn.
  335. [then]
  336.     -> xt  -> offs
  337.     offs -> emb_obj_offs                \ may need this in inline binding
  338.     xt
  339.     ^class offs  large_obj_array_check
  340. ;
  341.  
  342.  
  343. : <findIV>  { selID ^class \ ^ivar offs -- ^ivar offs xdispl-offs T | -- F  }
  344.  
  345. (*    Basic routine to look for an ivar.  It's not an error if we don't find it,
  346.     so we return a flag.
  347. *)
  348.     selID ^class  34 ( IFA_offset )
  349.     false (findm)  NIF  false  EXIT  THEN
  350.     
  351. [ ppc? not ] [if] 8 - [then]    \ 68k (findm) returns ^ivar + 8
  352.     -> ^ivar  -> offs            \ note - (findm) has returned the base
  353.                                 \  offs here - zero if not mult inherited
  354.     ^ivar 12 + w@  ++> offs
  355.     ^ivar
  356.     ^class offs  large_obj_array_check
  357.     true
  358. ;
  359.  
  360.  
  361. : ClFindM  { selID ^class -- cfa offs xdispl-offs }
  362.                                                 
  363. (*    finds a method's cfa given a selID and a class address, which hasn't
  364.     been checked for being in a module.  The returned results are as
  365.     described above for <findM>.
  366. *)
  367.     ^class ?>classInMod -> ^class
  368.     selID ^class  <findM>
  369. ;
  370.  
  371.  
  372. : ObjFindM  { selID ^obj \ ^class -- xt offs xdispl-offs
  373.                                 | -- xt offs 0 }
  374.  
  375. (* Finds a method's xt given a selID and an obj addr.  The returned
  376.     results are as described above for <findM>.
  377. *)
  378.     ^obj >class  -> ^class            \ will go into a module if nec
  379.  
  380.     ^class NIF  81 die  THEN        \ "not an object"
  381.     selID ^class  <findM>
  382. ;
  383.  
  384.  
  385. : IVFindM    \ ( selID ^ivar -- xt offs xdispl-offs )
  386. \  Looks for a method in an ivar.
  387.  
  388. \ Now we get the ivar's class - in the case of SELF, on the PPC it's
  389. \  tricky to put the current class into the dummy ivar info for SELF,
  390. \  but we can always tell if it's SELF from the offset.
  391.  
  392.     dup 12 + w@x -1 =
  393.     IF                    \ it's self - class is what we're compiling
  394.         drop ^comp_class
  395.     ELSE
  396.         8 + @abs        \ get addr of class from ivar info
  397.     THEN
  398.     clFindm  ;
  399.  
  400.  
  401. (*    ivFind is called when we've parsed a selector.  It determines if the next
  402.     word is an ivar.
  403.     Note: if found, <findIV> returns the equivalent of the cfa of
  404.     a method, which for ivars, is the addr of the class pointer.
  405. *)
  406.  
  407. : ivFind  { str-addr -- ^ivar offs xdispl-offs T |  -- str-addr F }
  408.     str-addr
  409.     cstate  NIF  false  EXIT  THEN
  410.     hash ^comp_class  <findIV>        \ ( ^ivar offs xdispl-offs  T  |  F )
  411.     IF        true
  412.     ELSE    [ ppc? ] [if] CDP [else] DP [then]  false
  413.     THEN
  414. ;
  415.  
  416.  
  417. PPC? not
  418. [IF]            \ want to get rid of conditional compilation via  ppc_only ,
  419.                 \  but stymied by call to PFind!  The following will be
  420.                 \  duplicated in zClass.
  421.  
  422. \ TOfind looks for a temp (local) object.
  423.  
  424. : TOfind  { str-addr -- ^ivar offs T | -- str-addr F  }
  425.     str-addr
  426.     tmpObjs  NIF  false  EXIT  THEN
  427.     hash
  428.     tmpObjs <findIV>
  429.     IF        drop        \ xdispl-offs must be zero for class Dummy
  430.             true
  431.     ELSE    str-addr false
  432.     THEN
  433. ;
  434.  
  435. (*
  436. LocFind will be called from Ufind, which is the vector that gets first
  437. shot at recognizing a word.
  438. It looks at all the possibilities involving local names, which are
  439. not in the regular dictionary.  These possibilities are: named parms/locals,
  440. local objects, and if a class is being compiled, ivars of this class.
  441.  
  442. In the latter case, we arrange for the ivar's address to
  443. be pushed at run time simply by compiling ^base followed by an add of the
  444. ivar's offset - our code generation will produce optimal code for this.
  445. We then have to return the xt of some word to keep FIND happy - we don't
  446. need to compile anything else, so we use the xt of NULL and return a 1
  447. instead of True - this makes FIND think it's immediate.  So NULL is
  448. executed immediately, which does precisely nothing.
  449.  
  450. The one exception to this is if the "ivar" turns out to be SELF or SUPER
  451. - in this case we need to call the nucleus word SELF which works out
  452. the right base address (this is what happened pre-2.5).  Here we keep
  453. FIND happy by pushing the xt of SELF and True, so that it sees we've
  454. found SELF.
  455. *)
  456.  
  457. : LocFind        \ ( str-addr -- cfa T  |  -- str-addr F )
  458.     Pfind    ?dup  ?EXIT                    \ Found a named parm/local
  459.     TOfind
  460.     IF                                    \ Found temp obj
  461.         drop                            \ Don't need its dic addr
  462.         postpone locReg  postpone literal  postpone +
  463.         ['] null  1   EXIT
  464.     THEN
  465.  
  466. \ Now we look for an ivar name
  467.  
  468.     cstate  NIF  false  EXIT  THEN        \ search fails if we're not compiling
  469.                                         \  a class
  470.  
  471.     dup hash ^comp_class 34 ( IFA_offset ) false  (findM)
  472.     IF                                    \ Found ivar
  473.         nip nip                            \ don't need embedded obj offs or
  474.                                         \  string addr
  475.         4+ w@                            \ ivar offset
  476.         dup $ FFFE >=                    \ is it SELF or SUPER (just used in
  477.                                         \  isolation)?
  478.         IF    drop  
  479.             " (^base) 4- dup w@x + 8 +" evaluate        \ i.e. SELF - but I can't evaluate
  480.                                                         \  that, or we'll end up here again
  481.                                                         \  and infinitely recurse!
  482.         ELSE
  483.             postpone (^base) postpone literal  postpone +
  484.         THEN
  485.         ['] null  1
  486.     ELSE    false
  487.     THEN  ;
  488.  
  489.  
  490. : ILFA     ( infa -- ilfa )    4+  ;
  491.  
  492.  
  493. : ^ICLASS  ( infa -- ^class | 0 )
  494.     8 + dup @ NIF   drop 0   ELSE   @abs ?>classInMod   THEN  ;
  495.  
  496.  
  497. : IOFFS    ( infa -- ioffs )    12 + w@  ;
  498. : I#ELS    ( infa -- #els )    14 + w@  ;
  499. : IFFA     ( infa -- iffa )    16 +  ;
  500.  
  501.  
  502. : ^NEXTIVAR    \ ( infa -- infa' )
  503.     ilfa  displace  ;
  504.  
  505. [THEN]
  506.  
  507.  
  508. ppc?
  509. [IF]
  510.  
  511. : EX-METHOD  { ^obj xt -- }
  512.  
  513.     meth_seg# 9 >
  514.     IF                    \ method's in a module
  515.         comp_seg#
  516.         IF        meth_seg# comp_seg#
  517.         ELSE    meth_seg#  mod_seg#
  518.         THEN
  519.         <>
  520.         IF                \ we're changing modules
  521.             ^obj  xt  meth_seg# segTable_entry 4+ @  meth_seg#  (meth_in_mod)
  522.             EXIT
  523.         THEN
  524.     THEN
  525.  
  526.     ^obj -> rY  xt execute
  527. ;
  528.  
  529.  
  530. (*    We use a cache to speed up late binding.  A hit means we get there in
  531.     150 instructions or so instead of 500, including the EXECUTE stuff.
  532.  
  533.     LB_cache entry format:
  534.     4 bytes        class reloc ptr
  535.     4 bytes        selID
  536.     4 bytes        method xt
  537.     2 bytes        offs
  538.     2 bytes        xdispl_offs
  539.     2 bytes        meth_seg# for target method
  540. *)
  541.  
  542.     variable    LB_cache        512 reservex
  543.  
  544.  
  545. 0        value    #hits
  546. 0        value    ^entry
  547. true    value    use_LB_cache?        \ for debugging
  548. 0        value    cache_dbgr            \ ditto
  549.  
  550.  
  551. : find_in_cache?  { classRP selID \ offs addr -- true | -- false }
  552.  
  553.     classRP selID xor  $ 1E0 and            \ 16-way hash, 32-byte blocks
  554.     LB_cache +  -> addr
  555.     use_LB_cache? nif false exit then
  556.  
  557.     addr @  classRP =
  558.     IF    addr 4+ @ selID =
  559.         IF            \ found!
  560.             1 ++> #hits
  561.             addr 8 + @                    \ meth xt
  562.             addr 12 + w@                \ offs
  563.             addr 14 + w@                \ xdispl_offs
  564.             addr 16 + w@  -> meth_seg#
  565.             
  566.             true  EXIT
  567.         THEN
  568.     THEN
  569.  
  570.     addr -> ^entry
  571.     false
  572. ;
  573.  
  574.  
  575. : SEND  { ^obj selID \ classRP svMC svMD addr -- }
  576.                 \ Executes a method given the object addr and the hashed
  577.                 \  selector.  Used in late binding.
  578.                 \  Can also be used if you have a dynamically determined
  579.                 \  method ID.
  580.  
  581.     ^obj >classRP @ -> classRP
  582.     classRP selID  find_in_cache?
  583.     NIF    
  584.         ^entry -> addr
  585.     
  586.         selID ^obj  objFindM    \ ( xt offs xdispl-offs | xt offs 0 )
  587.  
  588.         classRP        addr !
  589.         selID        addr 4+ !
  590.         meth_seg#    addr 16 + w!
  591.  
  592.         dup            addr 14 + w!
  593.         over        addr 12 + w!
  594.         2 pick        addr 8 + !
  595.     THEN
  596.     
  597.     ?dup
  598.     IF        ^obj + dup @ + +
  599.     ELSE    ^obj +
  600.     THEN
  601. \ ( xt ^obj' )
  602.     swap  ex-method
  603. ;
  604.  
  605. [THEN]
  606.  
  607.  
  608. PPC? not
  609. [IF]
  610.  
  611. \                        ========================
  612. \                                BINDING
  613. \                        ========================
  614.  
  615.  
  616. (*    Note: I think our obj_ind value might become obsolete on the PPC, since
  617.     we don't now use an indirect count in an OD, but just do repeated fetches
  618.     to different registers till we come to the data we want.
  619.     On the 68k, as far as I can tell, the only time obj_ind wasn't zero was
  620.     when we did an early bind to an addr on the stack, or to an objPtr (which
  621.     used the same code).  This was also the reason we kept two offsets
  622.     - obj_displ and obj_local_displ.  Obj_displ applied before any indirection
  623.     steps, and obj_local_displ after.  I think on the PPC these complexities
  624.     might be able to go away.
  625. *)
  626.  
  627.  
  628. : (OBJ)        \ Called from within an inline method.  Passes the object's
  629.             \  base and displacement to Handlers to generate the correct
  630.             \  address.  Optimization will then apply.
  631.  
  632.     obj_base obj_displ
  633.     obj_ind  genaddr
  634.     obj_local_displ  postpone literal  postpone +  ;
  635.  
  636.  
  637. : (IX)
  638.  
  639.     (*    Called from within an inline method.  Compiles code to generate
  640.         the indexed address.
  641.         ^comp_class has been set by inl_bind to the class of the obj
  642.         we're binding to.  One tricky point is that to access the indexed
  643.         area, we have to use the dlen value in this class, not the class
  644.         of the method we're calling (which may be a superclass).  But
  645.         the obj_local_displ has already had the embedded object offset
  646.         added in (if any).  We have to ignore this, since we're using 
  647.         the object's class, not the method's.  When the method was found,
  648.         the value emb_obj_offs was set to this offset, so we subtract
  649.         it here.
  650.     *)
  651.  
  652.     ^comp_class dlen&xwid  swap
  653.     self?
  654.     IF  drop  -1  ELSE  #off-align  6 +  THEN
  655.     obj_base obj_displ obj_local_displ
  656.     emb_obj_offs -
  657.     obj_ind  ^comp_class ffa w@
  658.     genxaddr  ;
  659.  
  660.  
  661. : ^BASE
  662.     compinline?
  663.     IF        (obj)
  664.     ELSE    postpone (^base)
  665.     THEN  ;            immediate
  666.  
  667.  
  668. : ^ELEM
  669.     compinline?
  670.     IF        (ix)
  671.     ELSE    " (^elem)"  evaluate            \ need PPC version
  672.     THEN  ;            immediate
  673.  
  674.  
  675. : OBJ    postpone ^base  ;    immediate        \ for backward compatibility
  676. : IX    postpone ^elem  ;    immediate        \ ditto
  677.  
  678.  
  679. local  EARLY_BIND  { oCfa oBase oDispl oLDispl oind slf? -- }
  680.  
  681.  
  682. : INL_BIND    \ ( -- b )
  683.     ^comp_class  cstate  self?                    \ Save over upcoming evaluate
  684.     slf? NIF  objClass -> ^comp_class  THEN        \ Set ^comp_class and cstate
  685.     true -> cstate                                \  so ivars are accessible
  686.     slf? -> self?
  687.     oCfa  inline_h
  688.     -> self?  -> cstate  -> ^comp_class            \ Restore
  689. ;
  690.  
  691.  
  692. : NORM_BIND
  693.     oCfa  (obj)  call_h  ;        \ call_h will see by the handler code
  694.                                 \  that this is a method, and do the
  695.                                 \  right things
  696.  
  697.  
  698. :loc  EARLY_BIND        \ { oCfa oBase oDispl oLDispl oind slf? -- }
  699.     obj_base  obj_displ  obj_local_displ  obj_ind        \ Save
  700.     oBase    -> obj_base            oDispl    -> obj_displ
  701.     OLdispl    -> obj_local_displ    oind    -> obj_ind
  702.  
  703.     oCfa 2- w@  $ BD40 =
  704.     IF      inl_bind
  705.     ELSE    norm_bind
  706.     THEN
  707.  
  708.     -> obj_ind  -> obj_local_displ
  709.     -> obj_displ  -> obj_base            \ Restore
  710. ;loc
  711.  
  712.  
  713. : BIND_TO_OBJ  { cfa ^obj offs -- }
  714.     cfa
  715.     -1                    \ -1 as "base" signals handlers to generate
  716.     ^obj                \  a normal dic addr.  We still carry the
  717.                         \  offs here since if we need to access the
  718.                         \  indexed area, we want the original obj addr,
  719.                         \  not some embedded object.
  720.     offs  0  false  early_bind  ;
  721.  
  722. : BIND_TO_STK    ( xt -- )
  723.     hStkObj  0  0  false  early_bind  ;
  724.  
  725. : BIND_TO_IVAR  { cfa offs -- }
  726.     cfa  obj_base  obj_displ
  727.     obj_local_displ offs +
  728.     obj_ind  false  early_bind  ;
  729.  
  730. : BIND_TO_TMPOBJ  { cfa offs -- }
  731.     cfa
  732.     4        \ locReg = D4 - %%% this will HAVE to change!!!
  733.     offs
  734.     0 0 false  early_bind  ;
  735.  
  736. : BIND_TO_SELF  { cfa offs -- }
  737.     cfa  obj_base  obj_displ  offs  obj_ind  true  early_bind  ;
  738.  
  739.  
  740. [THEN]
  741.  
  742.  
  743.  
  744. \                    ===========================
  745. \                     INITIALIZING NEW OBJECTS
  746. \                    ===========================
  747.  
  748.  
  749. PPC?
  750. [IF]
  751.  
  752. \ forward    INIT_IN_MOD            \ in zModules
  753.  
  754. : INIT_OBJ  { ^class ^obj \ xt offs -- }
  755.  
  756. (*    Performs CLASSINIT: method on object.
  757.  
  758.     Note, and this is important, we deliberately don't 
  759.     check if the offset would put us into the indexed area of a large_obj_array.
  760.     This is because we don't want to send CLASSINIT: individually to each of the
  761.     indexed elements, but instead we just send it to the base element.  Then,
  762.     CLASSINIT: in the large_obj_array class copies this to the indexed elements.
  763.  
  764.     In fact, we exploit this behaviour in setting up the code generator -
  765.     GPRs etc. are initialized via deep_classinit:, which calls init_obj here.
  766.     If we'd just done SEND, we would have tried to go into the indexed area,
  767.     and this would fail since the structure isn't set up yet!!
  768.  
  769.     So this is why we don't just call SEND here - we have to bypass the normal
  770.     method lookup process.
  771. *)
  772.  
  773. \    heldMod IF  ^class ^obj init_in_mod  EXIT  THEN
  774. \                                \ if it's in a module, zModules will handle
  775.     
  776.     initID  ^class  MFA_offset  true  (findm)
  777.     drop                        \ is guaranteed to find CLASSINIT: method
  778.     -> xt  -> offs
  779.     offs ++> ^obj                \ modify obj addr by offs (needed in case
  780.                                 \  method is defined in any superclass
  781.                                 \  but the first)
  782.     ^obj  xt  ex-method            \ execute classinit:
  783. ;
  784.  
  785. [ELSE]
  786.  
  787. \ For the target compilation, we can't send CLASSINIT: since we're still
  788. \  running on the 68k.  So INIT_OBJ is just a dummy.  We arrange things
  789. \  so that this doesn't matter for the stuff we're target compiling.
  790.  
  791. : INIT_OBJ   ( theClass theObj -- )
  792.     2drop  ;
  793.  
  794.  
  795. [THEN]
  796.  
  797.  
  798. : MAKE_HDRS        ( #els ) { ^class ^obj \ len wid ^xarea -- }
  799.     \ assumes ^class is the true class address, not
  800.     \ the main dictionary address of an exported class
  801.     \ if theClass is not indexed, there should be no #els on the stack
  802.  
  803.         0 -> ^xarea
  804.         ^class  (dlen&xwid)  -> wid  -> len
  805.  
  806.     \ first the xdesc (indexed area header), if indexed object
  807.  
  808.         wid
  809.         IF
  810.             len #off-align -> len
  811.             ^obj len +                    \ xdesc address: after ivars
  812.             dup 6 +  -> ^xarea            \ indexed hdr will be 6 bytes - save
  813.                                         \  indexed area addr
  814.  
  815.     ( #els ^xdesc )    wid over w!            \ two bytes: indexed width
  816.     ( #els ^xdesc )    swap 1- swap 2+ !    \ four bytes: limit ( #els-1)
  817.  
  818.  
  819.                 len 8 +                \ self-rel offset from class ptr to indexed
  820.                                     \  area to be put in obj header
  821.         ELSE    2                    \ standard offset if not indexed
  822.  
  823.         THEN
  824.  
  825.     \ now the obj header itself.  Note we leave the back ptr to the dic entry
  826.     \  alone, since it's been set already (or needs to remain zero, as the case
  827.     \  may be).
  828.  
  829.         ( offs )    ^obj 2- w!            \ 2 bytes: offset to indexed area
  830.                                         \  calculated above
  831.         ^class ?>maindic                \ don't store module addr of class!
  832.         false -> relocChk?                \ obj address could be in the heap!
  833.     ( ^comp_class )    ^obj 8 - reloc!        \ 4 bytes: relocatable class pointer
  834.         true -> relocChk?
  835.         -4 ^obj 4- w!                    \ 2 bytes: offset to class pointer --
  836.                                         \  always -4 for non-embedded object
  837. ;
  838.  
  839. 0 value bugtest
  840.  
  841.  
  842. forward IVSETUP
  843.  
  844. : NW_IVSETUP  { ^nway baseOffs EOoffs \ initEOoffs supClass supOffs adr -- }
  845.  
  846. (*    Sets up the groups of ivars for each superclass of the current object/ivar
  847.     being processed. One group for each super of a multiply inherited object.
  848.     Each group we call an "embedded object", which sort of describes what it is.
  849.     On entry ^nway points to the first superclass pointer in the n-way defining
  850.     the multiple inheritance. We repeat the procedure for each superclass until
  851.     the end marker (zero) is encountered. If the superclass is the pseudoclass
  852.     Meta we don't do anything since it does not have any ivars.
  853.  
  854.     baseOffs is the position of the current object/ivar's data space relative
  855.     to newObject, the current top-level object being created.
  856.     EOoffs is the offset from newObj at which the current embedded object
  857.     starts. When an embedded object starts at a non-zero EOoffs, we put in
  858.     front of it a 2-byte offset to the class pointer. Note that if the
  859.     multiply inherited object is an ivar, there may not be a class pointer!
  860.     This doesn't matter, since it's better for multiply inherited
  861.     objects to always have the same format, wherever they are, and any attempt
  862.     to use the class pointer offset to get the (nonexistent) class pointer
  863.     will most probably be caught by our checks.
  864. *)
  865.  
  866. \ we send classinit: separately to each superclass.
  867.  
  868.     EOoffs -> initEOoffs
  869.     BEGIN
  870.         ^nway @abs ?>classInMod  -> supClass    \ may hold a mod
  871.         supClass  c@ $ 80 and        \ is it META (which we don't call
  872.                                     \  ivSetup on, to end the recursion)?
  873.         NIF
  874.             baseOffs EOoffs +
  875.             initEOoffs -                \ Start of dataspace of this
  876.             -> supOffs                    \  superclass
  877.             supClass ifa displace            \ infa of first ivar of supClass
  878.             supOffs  EOoffs  ivSetup
  879.             supClass  newObject supOffs +  init_obj
  880.         THEN
  881.         ?unholdMod                        \ now finished with the mod
  882.         1cell ++> ^nway
  883.         ^nway @
  884.     WHILE        \ another class coming up - first store 2-byte ^class offset
  885.                 \  and 2-byte indexed area offset.  We have to 4-byte align
  886.                 \  first.
  887.  
  888.         supClass dfa w@                    \ dlen of supClass. Faster than using DLEN
  889.         #align4 ++> EOoffs                \ align - offsets will go here
  890.         EOoffs negate 8 -                \ ^class offset for store
  891.         EOoffs initEOoffs -                \ offset not already included in baseOffs
  892.         baseOffs + newObject +  -> adr    \ final addr for where offsets to be stored
  893.         adr w!
  894.  
  895.         newObject baseOffs +
  896.         2- w@ 2 <>            \ is object indexed?
  897.         IF
  898.             newObject baseOffs + 2- wdisplace  adr 2+ wdispl!
  899.                                         \ yes - store xarea offs
  900.         ELSE
  901.             2  adr 2+ w!                \ no - store 2
  902.         THEN
  903.         4 ++> EOoffs                    \ update EOoffs for next embedded obj
  904.     REPEAT  ;
  905.  
  906.  
  907. :f IVSETUP        { infa baseOffs EOoffs \ ivOffs ivClass -- }
  908.  
  909. (*    Recursively traverses the tree of nested ivar definitions in a class,
  910.     building headers and indexed area headers where necessary and applying
  911.     the CLASSINIT: method to each ivar.
  912.     On entry infa is the nfa of the first ivar in the ivar dictionary of the
  913.     object/ivar whose (sub)ivars we are to set up. The dictionary chain is
  914.     followed to the end, the last link pointing to the Nway superclass pointer.
  915.     baseOffs is the position of the current object/ivar's data space relative
  916.     to newObject, the current top-level object being created.
  917.     EOoffs is non-zero if the ivar whose subivars we are to set up is part
  918.     of an "embedded object", ie. is inherited from a superclass, and this
  919.     superclass is not the first super of the current top-level object.
  920.     This is given on unmodified in any recursive call and used only by
  921.     NW_IVSETUP to calculate the offset to the class pointer.
  922.     When this word is called, if the object/ivar's class is in a module,
  923.     the module will be held. In some circumstances the caller still needs it.
  924.     The recursive call might require another module to be held, so we have to
  925.     save and restore any module held on entry.
  926. *)
  927.     heldMod                \ If class is in module it must not get unheld
  928.                         \  while processing so keep address on the stack
  929.     0 -> heldMod        \  and clear heldMod so it cannot be unheld
  930.         
  931.     BEGIN
  932.         infa @ 0>    \ A selector is always negative, so a
  933.                     \  positive value means the N-way superclass
  934.                     \  pointer area ( superclass adresses ),
  935.                     \  the endpoint of the ivar dictionary chain
  936.                     
  937.     NWHILE    \ build this ivar in object
  938.  
  939.         infa iffa w@ 2 and            \ Static ivar? -> not in obj (bit 1)
  940.         NIF    infa ioffs                \ Offset of ivar in owning object
  941.             baseoffs +   -> ivOffs    \ Position relative to newObject
  942.             infa ^iclass -> ivClass    \ May cause another module to be held
  943.             infa iffa w@ 1 and        \ Does it want headers? -> flag bit 0
  944.             IF    infa i#els dup NIF drop THEN
  945.                 ivClass
  946.                 newObject ivOffs +     \ address where headers must be made
  947.                 make_hdrs
  948.             THEN
  949. \            ?Rdepth                    \ Check on recursion depth
  950.             ivClass ifa displace    \ Infa of first subivar in
  951.                                     \  chain of the currently
  952.                                     \  processed ivar object
  953.             ivOffs                    \ New base offset of subivar
  954.             0
  955.             ivSetup
  956.             ?unholdMod
  957.             ivClass  newObject ivOffs +  init_obj
  958.         THEN
  959.         infa ^nextivar -> infa
  960.     REPEAT
  961.  
  962.     infa baseOffs EOoffs  NW_ivSetup        \ set up superclasses
  963.     ( Heldmod )  -> HeldMod
  964. ;f
  965.  
  966.  
  967. \                    =================================
  968. \                            OBJECT BUILDING
  969. \                    =================================
  970.  
  971.  
  972. \ HASHED-HDR lays down the dic header for an ivar or method.
  973. \ The format is:
  974. \
  975. \ 4 bytes        hash
  976. \ 4 bytes        link (self-relative addr of prev entry)
  977. \
  978. \ This entry has to become the first on the chain, so we pass in the
  979. \ addr of the chain header.
  980.  
  981. : HASHED-HDR        \ ( chain-hdr hash-val -- )
  982.     code,                    \ comma in hash value
  983.     dup -> prev_link        \ save this in case a method gets moved
  984.     dup displace            \ get abs addr of prev entry
  985.     displCode,                \ comma it in as self-relative addr
  986.     CDP 8 -  swap  displ!    \ update chain header
  987. ;
  988.  
  989.  
  990. forward    DIC-OBJ
  991.  
  992. PPC?
  993. [if]
  994. : class_align  ( n ^class -- n' )
  995.     ffa w@ 8 >> $ F and ?dup 0EXIT
  996.     #align_2**n
  997. ;
  998. [then]
  999.  
  1000.  
  1001. : IVDEF  ( #els ) { iclass \ #els wid siz clOffs flags ^ccf -- }
  1002.         \ Compiles an ivar dictionary entry.  If indexed, must have
  1003.         \ < 64K elements.  iclass is the ivar's class.  The class of
  1004.         \ which this is an ivar, is pointed to by ^comp_class .
  1005.  
  1006.  
  1007.     pub/priv 1 =  4 and -> flags    \ initial flags - set bit 2 if we're public
  1008. [ ppc? ]
  1009. [if]
  1010.     iclass flags  register_check  -> flags
  1011.                                     \ update flags appropriately if this is a temp
  1012.                                     \  object in a register
  1013.     ^comp_class    ffa dup -> ^ccf
  1014.                     w@ $ F00 and
  1015.     iclass        ffa w@ $ F00 and  max
  1016.     ^ccf w@ $ F0FF and or  ^ccf w!
  1017.  
  1018. [then]
  1019.     Mword
  1020.     ivFind  IF 117 die  THEN        \ same name as another ivar
  1021.     drop                            \ drop string addr
  1022.     iclass xwid  -> wid                \ indexed width of ivar class
  1023.     iclass dlen  -> siz                \ non-indexed size of this ivar
  1024.     
  1025. \ The initial offset is the current dlen of the class.
  1026.  
  1027.     ^comp_class dfa w@  -> clOffs
  1028.     
  1029.     ^comp_class  ifa
  1030. [ ppc? ]
  1031. [if]  CDP  [else]  DP  [then]
  1032.     hash  hashed-hdr                \ dic header for ivar
  1033.  
  1034.     iclass ?>mainDic  relocCode,    \ class addr (reloc)
  1035.  
  1036. \ Now we need to comma in the 2-byte offset to the ivar within
  1037. \ the class.  First we need to make some adjustments...
  1038.  
  1039.     iclass ffa 1+ c@  4 and        \ general?
  1040.     dup 
  1041.     IF union? IF 190 die THEN
  1042.     THEN                \ (can't have a general object in a union)
  1043.     rec? not or            \ or not in a record?
  1044.     wid or                \ or indexed?
  1045.     IF                    \ Yes - in this case there'll be a 12-byte object
  1046.                         \  header which must be 4-byte aligned no matter
  1047.                         \  what, since the header has 4-byte fields.
  1048.         clOffs #align4 -> clOffs    \  align
  1049.         obj_hdr_length ++> clOffs    \  obj's data will start 12 bytes later
  1050.                                     \  than otherwise
  1051.         1 or> flags                    \ and we'll mark this in the ivar flags
  1052.                                     \  so make_hdrs will do the right thing.
  1053.                                     
  1054.     ELSE                \ No obj header.  Alignment depends on the ivar size.
  1055.                         \ Note that if the ivar class is multiply inherited
  1056.                         \   with >1 superclass of non-zero length, the ivar
  1057.                         \  size will always be >1.
  1058.         clOffs
  1059.         68k_align?
  1060.         IF    siz 1 > IF  #align2  THEN
  1061.         ELSE
  1062.             siz 2 >
  1063.             IF  #align4
  1064.             ELSE
  1065.                 siz 1 > IF  #align2  THEN
  1066.             THEN
  1067.         THEN
  1068.         -> clOffs
  1069.     THEN
  1070.  
  1071. \ but finally, if the class is asking for special alignment, we do that!
  1072.  
  1073. [ ppc? ]
  1074. [if]
  1075.     clOffs iclass  class_align  -> clOffs
  1076. [then]
  1077.  
  1078.     clOffs  codeW,
  1079.  
  1080.     wid
  1081.     IF                \ Indexed. Stack has #els.  We calculate the indexed
  1082.                     \ length of this ivar and increment clOffs.  We need
  1083.                     \ to off-align the non-indexed length, since the xdesc
  1084.                     \ is 6 bytes long with a 2-byte/4-byte layout.
  1085.         -> #els
  1086.         siz #off-align  -> siz        \ must off-align the non-indexed size, since
  1087.                                     \  the indexed hdr is 6 bytes long
  1088.         #els codeW,                    \ Add #els to ivar dic entry
  1089.         #els wid *                    \ Get indexed length
  1090.         6 +                            \ Add 6 for xdesc length    %%%%
  1091.         ++> clOffs                    \ Add to clOffs
  1092.     ELSE            \ Not indexed.
  1093.         0 codeW,
  1094.     THEN
  1095.     static?
  1096.     IF    2 or> flags
  1097.     ELSE
  1098.         siz ++> clOffs                \ Bump clOffs by non-indexed size of ivar
  1099.     THEN
  1100.  
  1101.     flags codeW,
  1102.     0 codeW,                        \ dummy for alignment
  1103.  
  1104. (* Now we'll update the class dLen field by whatever we're allocating for this
  1105.   ivar - it will then be the offset to the next ivar.  clOffs has the offset
  1106.   so far.  In the normal case, this is what goes in dLen.  If we're in
  1107.   a union, we MAX it with whatever's already in dLen.  This will leave dLen
  1108.   with the longest union element we've reached so far, which will be the final
  1109.   value in case we hit the end of the union.
  1110.   And if this ivar is static, it will live right where we are in the data
  1111.   area, and not in objects of the class, so in this case we leave dLen alone.
  1112.   We also do this if the "ivar" is really a temp object, and going into
  1113.   a register.
  1114. *)
  1115.     union?
  1116.     IF    
  1117.         unionOffs  clOffs  max  -> unionOffs
  1118.     ELSE
  1119.         flags 8 >> $ F and      \ register?
  1120.         static? or                \ or static?
  1121.         NIF                        \ neither, so update dLen.
  1122.             clOffs  ^comp_class dfa w!
  1123.         THEN
  1124.     THEN
  1125.  
  1126. (* Now we'll check if this ivar is to be static - if so, we'll instantiate
  1127.    it right now.  We put a reloc pointer in the code area, pointing to
  1128.    the ivar's data in the data area.  We leave the back pointer field in
  1129.    the ivar header zero, since there isn't a readable name in the code
  1130.    area.
  1131. *)
  1132.     static?  0EXIT
  1133.                         \ in data area:
  1134.     align4  obj_hdr_length reserve        \ align and reserve room for obj header
  1135.                         \ in code area:
  1136.     CDP
  1137.     0  code,
  1138.     DP swap reloc!            \ store reloc pointer to obj data in data area
  1139.  
  1140.     wid IF  #els  THEN
  1141.     iclass  dic-obj
  1142. ;
  1143.  
  1144.  
  1145. : CL>LEN ( #els ) { ^class \ wid len -- ( #els ) len2 }
  1146.                 \ Gets data length of object given #els and class.
  1147.     ^class dlen&xwid  -> wid  -> len
  1148.     wid
  1149.     IF    ( #els )  dup 32766 >
  1150.         IF  ^class ffa 1+ c@ 1 and  NIF 185 die  THEN
  1151.         THEN
  1152.          dup  wid *  6 +  len +
  1153.     ELSE    len
  1154.     THEN
  1155. ;
  1156.  
  1157.  
  1158. : MAKE_OBJ        ( #els ) { ^class ^obj \ svHeldMod -- }
  1159.  
  1160.     ^class ?>classinMod -> ^class        \ Need real class address,
  1161.                                         \  not main dic equivalent
  1162.     heldMod -> svHeldMod                \ If class is in module it must
  1163.                                         \  not get unheld while processing
  1164.                                         \  so keep the address and clear
  1165.     0 -> heldMod                        \  heldMod so it cannot be unheld
  1166.   ( #els ) ^class ^obj make_hdrs        \ Actually #els is optional element
  1167.                                         \  on the stack
  1168.         
  1169.     ^obj -> newObject                    \ base address used by ivSetup
  1170.     ^class ifa displace  0 0 ivSetup
  1171.     svHeldMod -> heldMod                \ held module (if any) no longer needed
  1172.     ^class ^obj init_obj                \ do a latebound CLASSINIT:
  1173.                                         \  on the object
  1174.     ?unholdMod
  1175. ;
  1176.  
  1177.  
  1178.  
  1179. : OBJ_HDR        \ creates a header for an object in the dictionary.    
  1180.                         \ in data area:
  1181.     align4  DP  obj_hdr_length reserve        \ align and reserve room for obj header
  1182.  
  1183.                         \ in code area:
  1184.                             \ ppc (create) not defined on 68k yet, so
  1185.                             \  we fake it:
  1186.     ppc_header
  1187.     $ BC0B  codeW,            \ handler code for objects.  We're now at
  1188.                             \  the cfa, and orig DP on stack.
  1189.     CDP swap reloc!            \ store "back pointer" at start of obj header
  1190.     0 codeW,                \ align
  1191.     CDP  0 code,
  1192.     DP swap reloc!            \ store reloc pointer to obj data in data area
  1193. ;
  1194.  
  1195.  
  1196. :f DIC-OBJ  ( #els ) { theClass \ ^obj svDP xx -- }
  1197.                 \ Builds an object in the dictionary.
  1198.  
  1199.     DP -> ^obj                        \ Where obj data will start
  1200.     theClass  cl>len  #align4        \ Required length for obj's data
  1201. \    dup room >  IF 999 die THEN        \ "Not enough room"
  1202.       reserve                            \ Allocate space for object
  1203.     theClass  ^obj  make_obj        \ Set up the object
  1204.     align4
  1205. ;f
  1206.  
  1207.  
  1208. (*    The next word builds an object.  On the 68k it's called PPC_OBJ, and
  1209.     is called from PPC_interpret (in cg6) when it sees the class
  1210.     handler code BC1D.
  1211.     On the PPC it's called CREATE_OBJ.  When we dispatch on the class
  1212.     handler code, we go to CLASS_H, which compiles a push of the xt of
  1213.     the class and then a call to here.  This will normally be done in
  1214.     interpret mode, which means it will be compiled into the execution
  1215.     buffer and executed straight away.  But a class name could be
  1216.     compiled into a definition and that should work as well.
  1217. *)
  1218.  
  1219. PPC?
  1220. [IF]
  1221.  
  1222. : create_obj    \ ( (#els) ^class -- )
  1223.  
  1224. [ELSE]
  1225.  
  1226. :f ppc_obj        \ ( (#els) ^class -- )
  1227.  
  1228. [THEN]
  1229.     cstate    IF                        \ compiling a class
  1230.                 ivDef                \ Build an ivar
  1231.             ELSE
  1232.             [ ppc? ] [if]
  1233.                 DP obj_hdr_length +  over  class_align
  1234.                 obj_hdr_length -  -> DP  
  1235.             [then]
  1236.                 obj_hdr                \ Create object header - returns
  1237.                                     \  its data address when called
  1238.                 dic-obj
  1239.             THEN
  1240. [ PPC? ]
  1241. [IF]  ;  [ELSE]  ;f  [THEN]
  1242.  
  1243.  
  1244. PPC?
  1245. [IF]
  1246. forward    call_h        \ the ppc defns of these aren't loaded yet
  1247. forward lit_addr
  1248.  
  1249.  
  1250. : CLASS_H  { xt \ xx -- }
  1251.     CDP -> xx
  1252.     xt lit_addr            \ compile a push of the xt
  1253.     ['] create_obj  call_h
  1254. ;
  1255.  
  1256.  
  1257. [THEN]
  1258.     
  1259. : HASH,        \ Compiles hashed word for name at CDP
  1260.     code_align        \ must be aligned    
  1261.     bl word  hash code,  ;
  1262.  
  1263.  
  1264. PPC? not
  1265. [IF]
  1266.  
  1267. \ Note: in PPC mode, this code is in zClass and is loaded straight on
  1268. \  the PPC, not target compiled (which gets horrendously complicated!).
  1269.  
  1270.  
  1271. \                    ============================
  1272. \                            :CLASS  etc.
  1273. \                    ============================
  1274.  
  1275. (*
  1276. Here we set up some quantities so that we can send messages to SELF
  1277. or SUPER.  These are treated syntactically as ivars, so to implement
  1278. them we actually set up dummy ivars SELF and SUPER.
  1279.  
  1280. When we're processing a :CLASS definition, we plug the appropriate
  1281. addresses into these ivars.  ^SELF is a word defined to return the
  1282. addr of the dummy ivar SELF, so we can do the plugging.
  1283. In the case of SUPER, there may be several superclasses, so we have
  1284. to go through a class descriptor, since that's the only place we look
  1285. for an n-way (a set of addresses).  So we set the "class" of SUPER
  1286. to a dummy class SUPCL, which has no ivars or methods (so the search
  1287. will pass right on by), and plug the superclass pointer of SUPCL to
  1288. point to the current n-way for the superclasses of the class we're
  1289. defining.
  1290. *)
  1291.  
  1292.  
  1293. \ META is the super class of Object - top of all inheritance
  1294.  
  1295. (*
  1296. Note that SUPCL, META etc. can't be set up before CROSS, since they have
  1297. to be in the PPC image.  But to set them up we have to have access to
  1298. 68k definitions.  So here with PPC? false, we define a defn that we
  1299. can execute after CROSS, which sets everything up before we try to compile
  1300. any classes.  We just call  define_meta  and it sets everything up.
  1301. *)
  1302.  
  1303.  
  1304. : define_meta  { \ ^ilink ^supcl -- }
  1305.     " META"    ppc_sHdr
  1306.     $ BC1D8000 code,        \ handler code, flags ($8000 = META)
  1307.     32 code_reserve            \ methods links - no methods
  1308.  
  1309.     CDP -> ^ilink
  1310.     0 code,                    \ ivar link - set to SUPER below
  1311.     0 code,                    \ dummy, data len
  1312.     0 code,                    \ indexed width, xdispl offs
  1313.     0 code,                    \ super pointer
  1314.  
  1315. \ Now we set up the SELF and SUPER pseudo-ivars.  We set them up exactly
  1316. \ as if they'd been declared as regular ivars in META.  But note we don't
  1317. \ set up any fields past the "offset" field, since they're irrelevant.
  1318.  
  1319.     " SUPCL"    ppc_sHdr
  1320.     $ BC1D0000 code,
  1321.     CDP 2- -> ^supcl
  1322.     32 code_reserve            \ methods links - no methods yet
  1323.     0 code,                    \ ivar link
  1324.     0 code,                    \ padding, dlen
  1325.     0 code,                    \ xwid, xdispl-offs
  1326.  
  1327. \ note: at superRef below, we need the addr of SUPER, so we tick SUPCL and
  1328. \  add the offset to SUPER which is (currently) 46 bytes.  So be careful
  1329. \  if moving anything!
  1330.  
  1331.     CDP                        \ ready for SELF link below
  1332.     " SUPER" pad place
  1333.     pad hash  code,
  1334.     0 code,                    \ empty link
  1335.     ^supcl  relocCode,        \ ^class is dummy supCl (reloc addr reqd)
  1336.     $ FFFE  codeW,            \ "offset" FFFE means SUPER
  1337.     0 codeW,                \ alignment
  1338.  
  1339.     CDP
  1340.     " SELF" pad place
  1341.     pad hash  code,
  1342.     swap  displCode,        \ link (to SUPER)
  1343.     0 code,                    \ ^class (gets patched at :CLASS time)
  1344.     $ FFFF  codeW,            \ "offset" FFFF means SELF
  1345.     0 codeW,                \ alignment
  1346.     
  1347.     dup    ['] (^self)    displ!    \ ^SELF will now return addr of SELF ivar
  1348.     ^ilink            displ!    \ META now has just 2 ivars - SELF and SUPER
  1349. \    " ' meta  metaAddr reloc!" evaluate
  1350. ;
  1351.  
  1352.  
  1353. : :CLASS
  1354.     ?exec  ppc_header  $ BC1D codeW,
  1355.     CDP -> ^comp_class
  1356.     0 -> pub/priv  0 -> #1st  0 -> #last
  1357.     false -> rec?  false -> union?  false -> static?
  1358.     307
  1359. ;        immediate
  1360.  
  1361.  
  1362. : MERGE_INFO  { ^sup ivlen \ ^wid wid prevWid -- dlen }
  1363.     ^sup dlen&xwid  -> wid        \ indexed width of this superclass
  1364.     ^sup ffa 1+ c@ 5 and        \ Merge "general" and "indexed" flags with
  1365.     ^comp_class ffa 1+  cset            \  what we have already
  1366.     wid  0EXIT                    \ If this superclass not indexed, we're done
  1367.     
  1368. \ This class is indexed - we need to check if prev classes were indexed
  1369. \  and make sure the widths are compatible.
  1370.  
  1371.     ^comp_class dfa 2+  -> ^wid        \ Addr of wid field in class we're building
  1372.     ^wid w@  -> prevWid            \ Get previous width
  1373.     wid 32760 u>                \ "indexed width" of 32766/7 really means
  1374.     IF                            \  obj_array.
  1375.         prevWid                    \ In this case if we already have a width,
  1376.         IF        prevWid -> wid    \  we use that,
  1377.         ELSE    wid
  1378.                 ivlen  -> wid    \ otherwise current ivar len becomes the width.
  1379.  
  1380.             ( old wid ) 32766 =
  1381.                 IF        \ large_obj_array - mark boundary between ivars
  1382.                         \  we are/aren't mapping to the indexed area
  1383.                     ivlen #align4  ^comp_class xoffa w!
  1384.                     wid #align4 4+  -> wid    \ and allow for ^class offset
  1385.                                             \  and indexed area offset
  1386.                                             \  before each element
  1387.                 THEN
  1388.         THEN
  1389.     THEN
  1390.     prevWid
  1391.     NIF     wid  ^wid w!        \ If no prev width, set width & we're done
  1392.     ELSE    prevWid wid <>  ?error 88        \ "Incompatible indexed widths"
  1393.     THEN
  1394. ;
  1395.  
  1396.  
  1397. local    (SUP)   { \ ^supcl ivlen ^nway ^sup ^newClass thisLen -- }
  1398.  
  1399. : NEXT_SUPER    ( cfa -- )
  1400.     chkClass  -> ^sup
  1401.     ^sup relocCode,                    \ Add ^class to n-way
  1402.     ^sup ivlen merge_info   -> thisLen
  1403.     #sup IF                            \ If this is a subsequent class,
  1404.         ivlen #align4  4+  -> ivlen    \  align and allow for ^class offset and
  1405.                                     \  2 extra bytes padding
  1406.     THEN
  1407.     thisLen ++> ivlen                \ And add ivar length of new class
  1408.     1 ++> #sup  ;
  1409.  
  1410.  
  1411. : SUPERS_LOOP
  1412.     BEGIN                        \ Loop over superclasses:
  1413.         '                        \ cfa of next item on list
  1414.         }or)? IF  drop  EXIT  THEN
  1415.         ( cfa )  next_super            \ handle next superclass
  1416.         1super?  ?EXIT                \ Yerk has only one superclass
  1417.     AGAIN  ;
  1418.  
  1419.  
  1420. :loc  (SUP)
  1421.     307 ?pairs                        \ Make sure we're in the right place
  1422.     CDP -> ^newClass
  1423.     46 ( classSize )  code_reserve            \ Space for class record
  1424.     CDP -> ^nway                    \ n-way for superclasses will
  1425.     0 -> ivlen  0 -> #sup            \  start here
  1426.     ^newClass 2+ 32 bounds
  1427.     DO  ^nway  i displ!  4 +LOOP    \ point methods links to nway
  1428.     ^nway ^newClass IFA  displ!        \ and ivars link
  1429.     false -> relocChk?
  1430.     supers_loop                        \ Loop over superclasses
  1431.     0 code,                            \ Terminate n-way
  1432.     " SUPCL" sFind drop -> ^supcl
  1433.     ^supcl 2+ 32 bounds
  1434.     DO  ^nway  i displ!  4 +LOOP    \ we point the method and ivar links
  1435.     ^nway                            \  in supcl to the n-way
  1436.     ^supcl IFA  displ!
  1437.  
  1438.     ^comp_class xoffa w@
  1439.     " SUPCL" sFind drop xoffa w!    \ and set xoffs in supCl
  1440.  
  1441.     ivlen ^comp_class dfa w!        \ Set total ivar length
  1442.     ^comp_class  ^self 8 +  reloc!    \ Store ^class in SELF
  1443.     true -> relocChk?
  1444.     postpone ]c                        \ In a class definition
  1445.     308
  1446. ;loc
  1447.  
  1448.  
  1449. : SUPER{        false -> 1super?   (sup)  ;        immediate
  1450.  
  1451. \ : SUPER(        postpone super{  ;                immediate
  1452.  
  1453. \ : <SUPER    true -> 1super?  (sup)    ;            immediate
  1454.             \ For compatibility with Yerk -- only looks for 1 superclass
  1455.  
  1456.  
  1457. : (;CL)
  1458.     postpone [  postpone c[
  1459.     0 ^self 8 + !  ;
  1460.  
  1461.  
  1462. : ;CLASS
  1463.     (;cl)  308 ?defn  ;            immediate
  1464.  
  1465.  
  1466.  
  1467. : M_HEADER  { selID -- }    \ Builds a method header and entry sequence.
  1468.                             \ Note: also called from the assembler.
  1469.     selID ^comp_class MFA  selID  hashed-hdr    \ Build header
  1470.     drop                            \ drop extra selID (needed by MFA)
  1471.     pub/priv -1 =  1 and  codeW,    \ public/private flag (default is public)
  1472.     0 codeW,                        \ padding for alignment
  1473.     $ BE400000 code,                \ "handler code" for PPC methods,
  1474.                                     \  and initial flag bytes
  1475.     CDP -> thisM                    \ Remember method cfa
  1476. ;
  1477.  
  1478. \    0 codeW,                        \ space for parm flags (or do it in Mentry?)
  1479. \    Mentry  ;                        \ Compile the entry sequence
  1480.  
  1481.  
  1482.  
  1483. : :M { \ selID -- }            \ Starts compiling a method.
  1484.     true -> method?
  1485.     ?class
  1486.     rec? ?error 191                    \ unmatched '{' in ivar list
  1487.     0 -> superM
  1488.     getSelect -> selID
  1489.     10 -> cstate                    \ Means we've read :m, no call_1st yet
  1490.  
  1491. (*    selID ^class 2 (findm)            \ is method already defined?
  1492.     IF
  1493.         -> superM
  1494.         warnings?
  1495.         IF    cr  0 -> out
  1496.             here count type type# 182             \ "Method redefined"
  1497.         THEN
  1498.         heldMod 
  1499.         NIF  superM ^class > ?error 183  THEN    \ - but if in same class, error
  1500.         drop
  1501.     THEN
  1502. *)
  1503.     get1st&last  ?unHoldMod
  1504.     CDP -> const_data_start
  1505.     selID m_header                    \ Build method header
  1506.     #1st #last +
  1507.     IF  $ 80  thisM 7 - cset  THEN    \ set call1st/callLast flag
  1508.     $ 74 -> obj_base                \ $60 + $14.   $60 says it's a PPC reg
  1509.                                     \  number, and gpr20 is obj base reg
  1510.     0 -> obj_displ                    \ For any inline method calls
  1511.     false ppc_entry                    \ Start to compile the method
  1512.  
  1513. \ we don't want to export any leaf methods, since we don't know anything
  1514. \  about them at the point of call.  This might be a bit of overkill, but
  1515. \  we'll fix the problem by not having any leaf methods in modules!  I don't
  1516. \  think it's worth trying anything cleverer.
  1517.  
  1518. [ ppc? ] [if]
  1519.     compmod IF  false -> leaf?  THEN
  1520. [then]
  1521.  
  1522.     drop 305                        \ change security marker to say method
  1523.     doCall1st  ;    immediate        \ Compile any Call1st calls first
  1524.  
  1525.  
  1526. : ;M
  1527.     curr-def 2-  (;)
  1528.     #last  IF  true -> method?  doCallLast  defnEnd  false -> method?  THEN
  1529.     0 -> #1st  0 -> #last
  1530.     305 ?defn  ;        immediate
  1531.  
  1532.  
  1533. \    ============== Local sections for methods ==============
  1534.  
  1535. \ These function just like regular local sections.  The implementation
  1536. \ is nearly the same.
  1537.  
  1538.  
  1539. : MLOCAL        \ Starts a local section for methods
  1540.     local?  ?error 93  1 -> local?        \ We change it to the normal -1
  1541.                                         \ as soon as "{" is read.
  1542.     postpone :m  drop
  1543.     postpone [
  1544.     CDP -> mloc_addr
  1545.     $ 48000000  code,        \ uncond branch to be resolved by :mloc
  1546.     private  ;
  1547.  
  1548.  
  1549. : :MLOC
  1550.     public  ?loc  getSelect drop
  1551.     CDP -> const_data_start
  1552.     $ BE030000  code,                \ marks this as the :mloc position
  1553.                                     \  (just for disassembly)
  1554.     false -> local?                    \ so entry sequence gets compiled
  1555.     false ppc_entry                    \ handle ppc proc entry
  1556.     drop 309                        \ security marker for :mloc
  1557.     curr-def
  1558.       mloc_addr -> curr-def
  1559.       PLentry
  1560.     -> curr-def
  1561.     frameSize IF  initTemps  THEN
  1562. ;        immediate
  1563.  
  1564.  
  1565. : ;MLOC
  1566.     309 ?defn
  1567.     false -> leaf?            \ let's just reduce the bug possibilities!
  1568.     mloc_addr 2-  (;)
  1569.     #last  IF  true -> method?  doCallLast  defnEnd  false -> method?  THEN
  1570.     0 -> #1st  0 -> #last
  1571.     curr-def mloc_addr -    \ finally we resolve the forward branch
  1572.     mloc_addr +!            \   from LOCAL
  1573. ;            immediate
  1574.  
  1575.  
  1576. \    ================   INDEXED, GENERAL etc.   =================
  1577.  
  1578. \ These are words which can appear in a class declaration, in the
  1579. \ position
  1580.  
  1581. \  :class someClass super{ someSuper }   general
  1582.  
  1583. \ They add attributes to the class.
  1584.  
  1585.  
  1586. : INDEXED        \ ( width -- )  Sets a class and its subclasses to indexed
  1587.     ?class  ^comp_class dfa 2+  w!  ;
  1588.  
  1589. : LARGE  ;        \ in effect, this always applies on the PPC
  1590.  
  1591.  
  1592. : GENERAL
  1593.  
  1594. (* Sets the "general" option on a class, which will force an ivar of that class
  1595.    to be a general object with a class pointer (so it can be late-bound to) even
  1596.    if it's within a record.  Normally you should just not put such ivars in a
  1597.    record, but using GENERAL gives a bit of extra security, for classes for which
  1598.    you know that they will definitely be late-bound to.  (An attempt to late-bind
  1599.    to an ivar without a class pointer will give the "not an object" error at run
  1600.    time, which isn't easy to track down.)
  1601.    Note that indexed classes are always general anyway.  Also if there's a message
  1602.    sent to [self] somewhere in one of the methods, we know that the class *must*
  1603.    be general, so in this case we simply set the general attribute.
  1604. *)
  1605. \    ?class  ^comp_class ffa 1+ dup c@ 4 or  swap c!  ;
  1606.  
  1607.     4 into_flags  ;
  1608.  
  1609.  
  1610. \                    ===========================
  1611. \                            SELECTORS
  1612. \                    ===========================
  1613.  
  1614. \ First, here are the special-purpose things which can follow a selector.
  1615. \ These can't appear in isolation.
  1616.  
  1617. \ We allow ** and [] as synonyms of [ ] to late-bind to whatever is on the
  1618. \ stack.  Note:  [] is used in JForth.
  1619.  
  1620. \ We also allow [self] as a synonym of [ self ]
  1621.  
  1622.  
  1623. : ]
  1624.     hide  dfrSelID  1 = IF   postpone ]  EXIT  THEN        \ if no late bind, this is a
  1625.                                                         \  standard Forth ]
  1626.     dfrSelID NIF  187 die  THEN        \ late bound pubilc ivar reference
  1627.                                     \  not implemented yet!
  1628.     state
  1629.     IF        251 ?pairs  dfrSelID  postpone literal
  1630.             " send" evaluate        \ need PPC version of SEND
  1631.     ELSE    $ deadbeef $ 106 db        \ shouldn't happen
  1632.             dfrSelID  send
  1633.     THEN
  1634.     1 -> dfrSelID  ;        immediate
  1635.  
  1636.  
  1637. (* REFTOKEN ( -- cfa tokenType | -- various type )
  1638.    is called when we've parsed a selector - it determines the type of the
  1639.    following word.
  1640.    
  1641.    The order of checking determines the priority of names.  Up to 2.6 we
  1642.    checked for locals first, but this was a bad idea since a local could
  1643.    have the same name as an object, and implicit late binding to locals
  1644.    was legal.  This wouldn't show up until a crash at run time.  So now we
  1645.    check for temp objects, then ivars, then locals IF implcit_late_bind? is
  1646.    true.
  1647.  
  1648.    "various" will be the cfa of whatever came after the selector, or
  1649.    ( offset ^ivar ) for ivars and temp objects (which are treated as ivars
  1650.    of the class Dummy).
  1651. *)
  1652.  
  1653. : REFTOKEN        \ ( -- cfa tokenType | -- various type )
  1654.  
  1655.     false -> need_class?
  1656.     Mword                                    \ grab next word
  1657.     TOfind    IF  tmpObjTyp    EXIT  THEN        \ check for temp object
  1658.     IVfind    IF  ivarTyp        EXIT  THEN        \ check for ivar
  1659.     
  1660.     implicit_late_bind?
  1661.     IF    Pfind    IF  locTyp    EXIT  THEN        \ check for named parm/locals
  1662.     THEN
  1663.  
  1664.     ( here )  dup thread dup @ +  (find)  0=  ?error 125
  1665.     dup ['] **            =  IF  lbTyp                            EXIT  THEN
  1666.     dup ['] []            =  IF  lbTyp                            EXIT  THEN
  1667.     dup ['] [            =  IF  bktTyp                            EXIT  THEN
  1668.     dup ['] [self]        =  IF  lbSelfTyp                        EXIT  THEN
  1669.     dup ['] super>        =  IF  superTyp                            EXIT  THEN
  1670.     dup ['] ivar>        =  IF  pubIvarTyp                        EXIT  THEN
  1671.     dup ['] class_as>    =  IF  true -> need_class?  classTyp    EXIT  THEN
  1672.     dup hdlr
  1673.     CASE
  1674.         objCode        OF    >obj  objTyp    ENDOF
  1675.         classCode    OF    classTyp        ENDOF
  1676.         -90            OF    classTyp        ENDOF        \ Exported class
  1677.         objPtrCode    OF    objPtrTyp        ENDOF
  1678.         valCode        OF    valTyp            ENDOF
  1679.         wordCode    OF    wordTyp            ENDOF
  1680.         vectCode    OF    wordTyp            ENDOF
  1681.                                 \ Note: here we can treat vectors as words.
  1682.  
  1683.         126 die                    \ "Not an object name"
  1684.     ENDCASE
  1685.  
  1686. \ but if we got wordTyp or valTyp, it's only legal if implicit_late_bind?
  1687. \  is true
  1688.     implicit_late_bind?  ?EXIT        \ all OK - done
  1689.     dup wordTyp =  over valTyp =  or
  1690.     IF  126 die  THEN
  1691. ;
  1692.     
  1693.  
  1694.  
  1695. \ These words handle the binding of a selector to whatever follows it.
  1696.  
  1697. (*    FIX_PIVAR does the housekeeping for accessing a public ivar.  When we
  1698.     encounter  msg: ivar>  then we store the selector in pivSel, and the
  1699.     hashed ivar name in pivar.  We then continue with a zero "selector",
  1700.     which signals that it's a public ivar access, and leads to us being
  1701.     called back here to fix everything up once we've got the class.
  1702. *)
  1703.  
  1704. : FIX_PIVAR  { ^class in_class? \ ^ivar offs xdispl-offs -- cfa offs xdispl-offs }
  1705.  
  1706.     pivar ^class <findIV>            \ ( ^ivar offs xdispl-offs true  OR  false )
  1707.     0= ?error 192                    \ "ivar not found"
  1708.     -> xdispl-offs  -> offs  -> ^ivar
  1709.     ^ivar iffa w@                     \ get ivar flags
  1710.     dup 4 and 0=    ?error 193        \ ivar not public
  1711.     2 and                            \ static flag
  1712.     in_class?
  1713.     IF        0=  ?error 197            \ ivar not static
  1714.     ELSE    ?error 195                \ wrong syntax for public static ivar
  1715.     THEN
  1716.  
  1717. \ now we find the method in the ivar's class
  1718.  
  1719.     pivSel ^ivar  ivFindm drop        \ %%% don't worry about large_obj_arrays
  1720.                                     \  which are ivars yet!
  1721.   ( cfa  offs-within-ivar )
  1722.     in_class?
  1723.     IF            \ for public static ivars, the "offset" we return is
  1724.                 \  actually the ivar's real data address.
  1725.         drop ^ivar  20 ( static_ivar_offs ) +  @abs  -> offs
  1726.     ELSE
  1727.         ++> offs
  1728.      THEN
  1729.      offs  xdispl-offs
  1730. ;
  1731.  
  1732.  
  1733. \ PUBLIC_STATIC_IVAR_REF handles a message bind to a public static ivar
  1734. \ (done via the  msg: ivar> in_class someClass  syntax)
  1735.  
  1736. : PUBLIC_STATIC_IVAR_REF
  1737.     refToken
  1738.     classTyp <>  ?error 196            \ class name must follow in_class
  1739.     true  fix_pivar drop            \ %%% don't worry about large_obj_arrays
  1740.                                     \  which are public static ivars yet!
  1741.     0  bind_to_obj
  1742. ;
  1743.  
  1744.  
  1745. \ OBJREF handles a reference to a normal object.
  1746.  
  1747. : OBJREF  { selID ^obj \ cfa offs xdispl-offs -- }
  1748.  
  1749.     selID
  1750.     IF    selID ^obj  objFindM
  1751.     ELSE                \ it's a public ivar reference in the referenced object
  1752.         ^obj >class  false  fix_pivar
  1753.     THEN
  1754.  
  1755.   ( cfa offs xdispl-offs )  -> xdispl-offs  -> offs  -> cfa
  1756.  
  1757.     xdispl-offs
  1758.     IF    
  1759.         ^obj xdispl-offs +  lit_addr
  1760.         " dup @ +" evaluate
  1761.         offs IF                \ will normally be zero
  1762.                 offs postpone literal
  1763.                 " +" evaluate
  1764.             THEN
  1765.         cfa bind_to_stk  EXIT
  1766.     THEN
  1767.  
  1768.      cfa ^obj offs bind_to_obj
  1769. ;
  1770.  
  1771.  
  1772. \ IVARREF handles a reference to an ivar.
  1773.  
  1774. : IVARREF  { selID ^ivar offs xdispl-offs \ cfa stat? -- }
  1775.     heldMod  0 -> heldMod                \ save
  1776.     offs  $ FFFE >=  -> selfRef?        \ if self or super.  Allows private
  1777.                                         \ methods to be found by (findm)
  1778.     selfRef?
  1779.     IF  supers_to_skip -> sups2skip        \ sups2skip is interrogated by (findm).
  1780.                                         \  This must only be done if self or
  1781.                                         \  super is the target.
  1782.         0 -> offs                        \ "real" offset is zero
  1783.     ELSE
  1784.         ^ivar iffa w@ 2 and  -> stat?    \ static ivar?
  1785.     THEN
  1786.     selID
  1787.     IF    selID ^ivar ivFindM            \ %%% don't worry about large_obj_arrays
  1788.                                     \  which are ivars yet!
  1789.         selfRef? IF -> xdispl-offs  ELSE drop THEN
  1790.  
  1791.         ++> offs                    \ add embedded obj base offs to ivar offs
  1792.         -> cfa
  1793.         0 -> sups2skip  0 -> supers_to_skip
  1794.  
  1795.         selfRef?
  1796.         IF    xdispl-offs
  1797.             IF    xdispl-offs postpone literal
  1798.                 " ^base + dup @ +"  evaluate
  1799.                 cfa  bind_to_stk
  1800.             ELSE
  1801.                 cfa offs bind_to_self  false -> selfRef?
  1802.             THEN
  1803.             ?unholdMod  -> heldMod   EXIT
  1804.         THEN
  1805.  
  1806.     ELSE                \ it's a public ivar reference within the referenced ivar
  1807.         ^ivar ^iclass false  fix_pivar drop        \ %%% don't worry about large_obj_arrays
  1808.                                                 \  which are ivars yet!
  1809.         ++> offs  -> cfa
  1810.     THEN
  1811.  
  1812.     stat?
  1813.     IF    cfa ^ivar 26  bind_to_obj
  1814.         ?unholdMod  -> heldMod  EXIT
  1815.     THEN
  1816.     
  1817.     xdispl-offs
  1818.     IF    xdispl-offs postpone literal
  1819.         " ^base + dup @ +"  evaluate
  1820.         offs IF                        \ will normally be zero
  1821.                 offs postpone literal  " +" evaluate
  1822.             THEN
  1823.         cfa  bind_to_stk
  1824.     ELSE
  1825.         cfa offs  bind_to_ivar
  1826.     THEN
  1827.     ?unholdMod  -> heldMod
  1828. ;
  1829.  
  1830.  
  1831. \ OP/CL is common code factored out of objPtrRef and classRef, which
  1832. \ are very similar.
  1833.  
  1834. : OP/CL  { selID ^class \ cfa offs xdispl-offs -- }
  1835.     selID
  1836.     IF    selID ^class clFindm
  1837.     ELSE
  1838.         ^class  false  fix_pivar
  1839.     THEN
  1840.     -> xdispl-offs  -> offs  -> cfa
  1841.  
  1842.     xdispl-offs
  1843.     IF    xdispl-offs postpone literal
  1844.         " + dup @ +"  evaluate
  1845.     THEN
  1846.     
  1847.     offs postpone literal  " +" evaluate
  1848.     cfa bind_to_stk
  1849. ;
  1850.  
  1851.  
  1852. \ OBJPTRREF handles a reference to an object pointer.
  1853.  
  1854. : OBJPTRREF  { selID OP-cfa \ OPclass cfa offs xdispl-offs addr -- }
  1855.     OP-cfa  (comp)                    \ Compile a fetch of the OP-cfa,
  1856.                                     \  giving ^obj at run time
  1857.     OP-cfa 2+ @abs  -> addr
  1858.     addr 4+ @abs  -> OPclass
  1859.     OPclass  0= ?error 86            \ "ObjPtr hasn't had a class specified"
  1860.     OPclass hdlr -90 =
  1861.     IF                                \ Class is exported
  1862.         OPclass 6 + wdisplace        \ Addr of module
  1863.         compmod =  ?error 84        \ It's the module we're compiling -
  1864.                                     \  this is a no-no, since the ObjPtr
  1865.                                     \  reference will use the OLD module!
  1866.         OPclass  ?>classInMod -> OPclass
  1867.     THEN
  1868.     selID OPclass  OP/cl
  1869. ;
  1870.  
  1871. \ CLASSREF handles a reference to a class - this means use the object
  1872. \  whose addr is on the stack, but ASSUME it is of the given class
  1873. \  and early bind, without checking.
  1874. \ The code is very similar to objPtrRef, naturally enough.
  1875.  
  1876. : CLASSREF { selID ^class \ cfa offs xdispl-offs -- }
  1877.     need_class? IF  '  chkClass -> ^class  false -> need_class?  THEN
  1878.     selID ^class  OP/cl
  1879. ;
  1880.  
  1881.  
  1882. \ TMPOBJREF handles a reference to a temp object.
  1883.  
  1884. : TMPOBJREF  { selID offs ^tmpObj \ svHeldMod cfa xdispl-offs -- }
  1885.     heldMod -> svHeldMod  0 -> heldMod
  1886.     selID
  1887.     IF    selID ^tmpObj ivFindM
  1888.     ELSE
  1889.         ^tmpObj 8 + @abs  false  fix_pivar
  1890.     THEN
  1891.     -> xdispl-offs  ++> offs  -> cfa
  1892.  
  1893.     xdispl-offs
  1894.     IF    postpone locReg
  1895.         xdispl-offs postpone literal  postpone +
  1896.         postpone dup postpone @ postpone +
  1897.         offs IF  offs postpone literal  postpone +  THEN    \ will normally be zero
  1898.         cfa  bind_to_stk
  1899.     ELSE
  1900.          cfa offs  bind_to_tmpObj
  1901.         svHeldMod -> heldMod
  1902.     THEN
  1903. ;
  1904.  
  1905.  
  1906. \ SuperRef handles the  msg: super> someSuper  construct.
  1907.  
  1908. : SUPERREF { selID \ ^nway namedClass ^nway' cnt -- }
  1909.     ?class                            \ Must be compiling a class
  1910.     '  -> namedClass                \ get named class xt
  1911.     ^comp_class sfa -> ^nway
  1912.     ^nway -> ^nway'  0 -> cnt
  1913.     BEGIN
  1914.         ^nway' @ 0= ?error 120            \ "superclass" not found
  1915.         ^nway' @abs namedClass =
  1916.     NWHILE
  1917.         1cell ++> ^nway'  1 ++> cnt
  1918.     REPEAT
  1919.     cnt -> supers_to_skip
  1920.     selID
  1921.     " SUPCL" sFind drop 46 +    \ careful of hard-coded number here
  1922.     $ FFFE  0  ivarRef            \ equivalent to msg: super
  1923. ;
  1924.  
  1925.  
  1926. forward COMPREF
  1927.  
  1928. \ PubIvarRef handles the  msg: ivar> someIvar IN someObj  construct, to
  1929. \  send a message directly to a public ivar in an object.  At this point
  1930. \  we've just read "ivar>".
  1931.  
  1932. : PUBIVARREF  { selID \ addr len ^class ^ivar -- }
  1933.     selID -> pivSel                    \ save selID being sent to the ivar
  1934.     mword hash  -> pivar            \ parse ivar name
  1935.     mword count  -> len  -> addr
  1936.     addr len  " IN" s=
  1937.     IF    0                 \ dummy "selID" for compRef (not a legal selector)
  1938.         compRef            \ handle whatever object comes after IN.  The
  1939.                         \  zero selector signals that a public ivar in the
  1940.                         \  indicated object is to be accessed - real selectors
  1941.                         \  can't ever be zero.  This will lead to fix_pivar
  1942.                         \  being called to complete the job.
  1943.     ELSE
  1944.         addr len " IN_CLASS" s=
  1945.         IF        public_static_ivar_ref
  1946.         ELSE    true ?error 194        \ "wrong syntax for public ivar"
  1947.         THEN
  1948.     THEN
  1949. ;
  1950.  
  1951.  
  1952. \ LBselfRef handles messages to [self] - i.e. late bound to Self.
  1953.  
  1954. : LBSELFREF  ( selID -- )
  1955.     " self" evaluate  postpone literal        \ pushes ^self, then selID
  1956.     " send" evaluate                        \ ppc send
  1957. ;
  1958.  
  1959.  
  1960. \ Now here are the main words which compile the selector bindings.
  1961.  
  1962. \ CompRef operates at compile time - it compiles a selector bind.
  1963.  
  1964. :f COMPREF        \ ( selID -- )
  1965.  
  1966.     refToken    \ ( selID <various> type )
  1967.                 \    <various> will be the cfa of whatever came after the selector,
  1968.                 \    or ( offset ^ivar ) for ivars and temp objects (which are
  1969.                 \    treated as ivars of the class Dummy).
  1970.  
  1971.     CASE
  1972.         objTyp        OF  objRef                            ENDOF
  1973.         ivarTyp        OF    ivarRef                            ENDOF
  1974.         objPtrTyp    OF  objPtrRef                        ENDOF
  1975.         tmpObjTyp    OF  tmpObjRef                        ENDOF
  1976.         classTyp    OF    classRef                        ENDOF
  1977.  
  1978. \ These next 3 can only come up if implicit_late_bind? is true:
  1979. \        valTyp        OF  compdfr                            ENDOF
  1980. \        locTyp        OF  compdfr                            ENDOF
  1981. \        wordTyp        OF  compdfr                            ENDOF
  1982.  
  1983.         lbTyp        OF  drop  postpone literal
  1984.                         " send" evaluate  ( ensure we get ppc "send" )
  1985.                                                         ENDOF
  1986.         lbSelfTyp    OF  drop  LBselfRef                    ENDOF
  1987.         bktTyp        OF  drop  -> dfrSelID  251            ENDOF
  1988.         superTyp    OF    drop  superRef                    ENDOF
  1989.         pubIvarTyp    OF    drop  pubIvarRef                ENDOF
  1990.  
  1991.         82 die                        \ "Selector can't be used on that"
  1992.         
  1993.     ENDCASE
  1994.     update_refcnts
  1995.  
  1996. ;f
  1997.  
  1998.  
  1999. (*
  2000. RunRef is the execution mode equivalent - it executes a selector bind.
  2001. We do this simply by compiling it in a buffer then executing it there.
  2002. This replaces the earlier scheme where we had to separately handle each
  2003. case as for compRef - this was a Neon carryover.
  2004.  
  2005. While we're compiling in the buffer, we save the DP on the return stack,
  2006. then restore it before executing what we compiled (since it might do some
  2007. compiling itself).  This isn't long, but it's a bit tricky:
  2008. *)
  2009.  
  2010.  
  2011. : RUNREF  { selID \ svDP svBufPtr svState -- }
  2012.     DP -> svDP                \ save DP
  2013.     DP hiDP umax -> hiDP    \ so we can reset DP to right place on an error
  2014.  
  2015.     bufPtr NIF  runRefBuf  ELSE  bufPtr  THEN
  2016.     dup -> DP  -> svBufPtr    \ now we'll compile in runRefBuf
  2017.     state -> svState        \ save state
  2018.     postpone ]            \ need compile state so this compilation works properly
  2019.     selID compRef        \ compile the binding
  2020.     svState -> state    \ restore state
  2021.     0 -> hiDP            \ don't need it any more and could cause problems
  2022.     ?unholdMod
  2023.     DP -> bufPtr        \ new bufPtr value
  2024.     svDP -> DP            \ restore DP since the code might compile something
  2025.     patches_done        \ we're about to execute what we just compiled
  2026.     svBufPtr execute    \ execute at old bufPtr location
  2027.     svBufPtr -> bufPtr    \ then restore old bufPtr
  2028. ;
  2029.  
  2030.  
  2031. \                ======== Selector support =========
  2032.  
  2033.  
  2034. \ MESSAGE is the handling word invoked by using a selector.
  2035.  
  2036. : MESSAGE        immediate
  2037.     state
  2038.     IF                      \ Compile state
  2039.         compRef                \ Compile the message send
  2040.         ?unHoldMod
  2041.     ELSE
  2042.         runRef                \ Run state - execute object/vector reference.
  2043.                             \ ?unHoldMod is called by ex-method at the
  2044.                             \ end, so we don't need to call it here.
  2045.     THEN  ;
  2046.  
  2047.  
  2048. \ 1stFind lumps together all the special cases we have to look for after
  2049. \ we've parsed an input word, but before we can do a regular dictionary
  2050. \ lookup.  At present these are selectors, named parms/locals, ivars
  2051. \ and local objects.  If we invent more later, they can easily be added.
  2052. \ The vector Ufind is then set to this word so it is called before the
  2053. \ regular dictionary search.  If we succeed here, we return the selector
  2054. \ ID or zero, the cfa of the handling word, and 1 or -1 (this will cause
  2055. \ FIND to exit without doing anything more).  If we fail, we return the
  2056. \ original string address and false.
  2057.  
  2058. : 1stFIND    \ ( str-addr -- selID message-cfa T  |  -- str-addr F )
  2059.     sel?                        \ is it a selector?
  2060.     IF        hash                \ yes - leave selID
  2061.             ['] message  1        \  and cfa of message, and 1 (it's immediate)
  2062.     ELSE    LocFind                \ no - look for the various kinds of local name
  2063.     THEN  ;
  2064.  
  2065.  
  2066. ' 1stFind -> Ufind
  2067.  
  2068.  
  2069. \ : OBJLEN    \ ( -- objlen )  Computes total data length of current object.
  2070. \
  2071. \    ^base (^dlen)  dup w@  swap 2+ w@  ?dup
  2072. \    IF  idxBase 4- @ 1+  *  + 4+  THEN   ;
  2073.  
  2074.  
  2075. getSelect classinit:  -> initID
  2076.  
  2077.  
  2078. \ forward DUMP
  2079.  
  2080.  
  2081. \ SET_CLASS is a utility word used to patch nucleus objects when their classes
  2082. \ are defined in higher-level files.  Actually it could be used to change the
  2083. \ class of any object, if anyone is silly enough to want to do that.
  2084.  
  2085. \ Usage:  fFcb  ['] file  set_class
  2086.  
  2087. : SET_CLASS  { ^obj theClass -- }
  2088.     theClass  chkClass  ^obj 8 -  reloc!        \ Patch ^class
  2089.     2  ^obj  2-  w!                    \ Not indexed (yet)
  2090.     -4 ^obj  4-  w!  ;                \ ^class offset
  2091.  
  2092.  
  2093. : CHKSAME        \ ( ^obj -- ^obj )
  2094.         \ A check that two objects are of exactly the
  2095.         \ same class.
  2096.     dup >classXt  ^base >classXt  <> ?error 87  ;
  2097.  
  2098.  
  2099.  
  2100.  
  2101. \            ========= Object pointers ==========
  2102.  
  2103. (*    Object pointers are low-level objects (like VALUEs) which point to a
  2104.     normal (high-level) object, and which allow early-bound messages to be
  2105.     sent to the object by syntactically sending them to the object pointer.
  2106.  
  2107.     The normal syntax is
  2108.  
  2109.     ObjPtr  ZZZ    class_is  someClass
  2110.  
  2111.     Thereafter, any messages sent to zzz are early-bound to the object that
  2112.     zzz points to at the time the message executes.
  2113.  
  2114.     If you need to declare the object pointer before the class exists, use
  2115.     SET_TO_CLASS once the class is defined, thus:
  2116.  
  2117.     :class  SOMECLASS    super{ object }
  2118.  
  2119.     ' someOP  set_to_class  someClass
  2120.  
  2121.     etc.
  2122. *)
  2123.  
  2124.  
  2125. : (toOP)  { ^obj OPcfa \ OPclass addr -- }
  2126.  
  2127.     OPcfa 2+ @abs -> addr        \ note: in the PPC native version (see right
  2128.                                 \  near the end), litAddr_h does this for us.
  2129.  
  2130.     ^obj  nilP =                \ If we're storing nil, anything goes
  2131.     check_OP_stores? not or        \ Or if checking is turned off
  2132.     NIF    
  2133.         addr 4+ @abs -> OPclass
  2134.         ^obj 8 - @abs OPclass  <>
  2135.         IF                          \ Mismatch. We give some useful(?) info.
  2136.             cr  ^obj obj> .id ."  -> "  OPcfa .id
  2137.             87 die
  2138.         THEN
  2139.     THEN
  2140.     ^obj addr !
  2141. ;
  2142.  
  2143.  
  2144. :f  ToObjPtr
  2145.     state
  2146.     IF  litAddr_h  " (toOP)" evaluate  ELSE  (toOP)  THEN  ;f
  2147.  
  2148.  
  2149. : CLASS_IS    \ ( --< class > )
  2150.     ?exec  '  chkClass  DP 4-  reloc!  ;
  2151.  
  2152.  
  2153. \        ===================================
  2154.  
  2155. \ Bytes is used as the allocation primitive for basic classes
  2156.  
  2157. : BYTES  { numBytes \ svRec? -- }
  2158.     ?class
  2159.     rec? -> svRec?  true -> rec?            \ Don't want an object header here
  2160.     " object" sFind drop  ivDef
  2161.     numBytes  ^comp_class dfa  w+!
  2162.     svRec? -> rec?  ;
  2163.  
  2164.  
  2165. \ Temp objects aren't needed for the code generator, so we defer them
  2166. \  to zClass, which simplifies life considerably.
  2167.  
  2168.  
  2169. (*        =================  Records and unions  ====================
  2170.  
  2171. Syntax:
  2172.  
  2173.     record <name>        \ The name is optional
  2174.    {    var        v1
  2175.         int        i1
  2176.         string    s
  2177.    }
  2178.    
  2179.        union <name>        \ The name is optional
  2180.    {    var        v1
  2181.         int        i1
  2182.         string    s
  2183.    }
  2184.  
  2185.  
  2186. Or you can use record{ ...  } or union{ ... } if you prefer, if it's
  2187. unnamed.  The similarity of syntax to temp objects is quite deliberate.
  2188. But any similarity to Your Favorite Language is entirely accidental.  Well
  2189. actually it's not, but I think this syntax is as good as any, and probably
  2190. more readable for folks coming from the land of C.
  2191.  
  2192. unions can be nested within records and vice versa.
  2193.  
  2194. NOTE: it's best to not use unions unless you're really sure you know what
  2195. you're doing.  Having different objects sharing the same memory is sure
  2196. to cause problems if you're careless!
  2197.  
  2198. *)
  2199.  
  2200. : SVREC        
  2201.    ^comp_class dfa w@ 
  2202.     rec?  union?  unionOffs  68k_align?
  2203. ;
  2204.  
  2205. : RSTREC
  2206.     -> 68k_align?  -> unionOffs  -> union?  -> rec?  
  2207.     union? IF     \ we fell back in a union, so we
  2208.                 \ reset data pointer to where it was at the beginning
  2209.                 \ of this union/rec
  2210.         ^comp_class dfa w!
  2211.     ELSE
  2212.         drop
  2213.     THEN
  2214. ;
  2215.  
  2216. : ?HANDLE_NAME  { \ sv_>in sv_^class sv_rec? -- }
  2217.     >in @ -> sv_>in ^comp_class -> sv_^class  rec? -> sv_rec?
  2218.     Mword  count  " {" s=
  2219.     NIF                            \ we've got a name for the record
  2220.         true -> rec?            \ must do this before defining the name "object"
  2221.         sv_>in  >in !
  2222.         " object" sFind drop  ivDef
  2223.         sv_rec? -> rec?  sv_^class -> ^comp_class
  2224.         gobble{                    \ "{" must follow
  2225.     THEN
  2226. ;
  2227.  
  2228.  
  2229. : }RECORD
  2230.     131 ?pairs  rstRec
  2231.     ['] } >body !  ;
  2232.  
  2233.  
  2234. : RECORD{
  2235.     ?class                        \ must be compiling a class
  2236.     ['] } >body @                    \ save old action for "}"
  2237.     ['] }record  -> }            \ "}" will now be same as }record
  2238.     svRec                        \ save parameters for any existing record/union
  2239.     131                            \ for ?pairs
  2240.     true -> rec?  false -> union?  ;
  2241.  
  2242. : RECORD
  2243.     ?handle_name
  2244.     record{  ;
  2245.  
  2246. : 68k_RECORD{
  2247.     record{
  2248.     true -> 68k_align?  ;
  2249.  
  2250. : 68k_RECORD
  2251.     record
  2252.     true -> 68k_align?  ;
  2253.  
  2254.  
  2255. : }UNION
  2256.     132 ?pairs
  2257.     unionOffs  ^comp_class dfa w!    
  2258.     rstRec
  2259.     ['] } >body !  ;                \ restore old action for "}"
  2260.  
  2261. : UNION{
  2262.     ?class                        \ must be compiling a class
  2263.     ['] } >body @                    \ save old action for "}"
  2264.     ['] }union  -> }            \ "}" will now be same as }union
  2265.     svRec                        \ save record/union parameters
  2266.     132                            \ for ?pairs
  2267.     true -> rec?  true -> union?
  2268.     ^comp_class dfa w@ -> unionOffs  ;
  2269.  
  2270.  
  2271. : UNION
  2272.     ?handle_name
  2273.     union{  ;
  2274.  
  2275.  
  2276. \ This is for finding a bug:
  2277.  
  2278. : TCHK  { thread# \ thread_addr lfa -- }
  2279.  
  2280.     thread# dummy_len c!                \ fake a "length byte" for THREAD
  2281.     dummy_len thread  -> thread_addr    \ addr of thread start in CONTEXT
  2282.     
  2283.     thread_addr displace  -> lfa        \ addr of first link field in thread,
  2284.                                         \  in CONTEXT
  2285.     BEGIN
  2286.         ?pause
  2287.         lfa displace                    \ chain back
  2288.         dup code_start u<
  2289.         IF    drop        \ next link field is below start of code
  2290.             EXIT
  2291.         THEN
  2292.         ." lfa: " lfa .h 3 spaces  lfa link> .id  cr
  2293.         -> lfa
  2294.     AGAIN
  2295. ;
  2296.  
  2297. endload
  2298.  
  2299. [THEN]        \ ppc? not [if]
  2300.  
  2301. (*    Thus before CROSS, the first time through, we stop there.
  2302.     We now define OBJECT and optionally the torture tests, in target
  2303.     compilation mode.
  2304. *)
  2305.  
  2306.  
  2307. \        ===================================
  2308.  
  2309. forward dump
  2310.  
  2311. forward    I/O_ERR        \ ( err# -- )  Call when there's an I/O error.
  2312.  
  2313. : OK?        \ ( rc -- )  A useful word to use after an I/O op.
  2314.     ?dup  0EXIT  I/O_err  ;
  2315.  
  2316. variable    self_vbl
  2317.  
  2318. define_meta
  2319.  
  2320. ^self  self_vbl  displ!x
  2321.  
  2322.  
  2323.  
  2324.  
  2325. : CAN_BE_GPR        $ 30  into_flags  ;
  2326. : CAN_BE_FPR        $ 40  into_flags  ;
  2327. : CAN_BE_VR            $ 50  into_flags  ;
  2328.  
  2329. : ALIGNMENT  ( n -- )  8 << into_flags  ;        \ n is power of 2
  2330.  
  2331.  
  2332.  
  2333. :class    OBJECT    super{ meta }
  2334.  
  2335. :m CLASS:    ^base ?>class ( ?>classinMod )  ;m
  2336.  
  2337. :m GETNAME:    ( -- addr len )
  2338.     ^base obj>
  2339.     ?dup IF  >name n>count  ELSE  " <no name>"  THEN  ;m
  2340.  
  2341. :m .ID:        getName: self  type  ;m
  2342.  
  2343. :m .CLASS:    ^base >classXt  .id  ;m
  2344.  
  2345. :m ADDR:    inline{ ^base}  ;m
  2346.  
  2347. \ :m ABS:        ^base  ;m        \ now obsolete
  2348.  
  2349. :m LENGTH:    \ ( -- len )  Gets total length of object.
  2350.     objlen  ;m
  2351.  
  2352. :m #ELEMENTS:  ( -- #elems )
  2353.     ^base (^dlen)  2+ w@        \ indexed width
  2354.     IF            \ we're indexed
  2355.         idxBase 4- @ 1+
  2356.     ELSE        \ not indexed - return -1
  2357.         -1
  2358.     THEN
  2359. ;m
  2360.  
  2361.  
  2362. (*    Here are two methods which operate between this object and another of
  2363.     the same class.  Note we don't check that the passed-in object is actually
  2364.     of the same class, since it could be a subclass but still be safe to use
  2365.     here.
  2366. *)
  2367.  
  2368. :m COPYTO:    \ ( ^obj -- )  Copies the ivar part of the passed-in object
  2369.             \ to self.
  2370.     ^base  dup (^dlen) w@  aligned_move  ;m
  2371.  
  2372. :m =?:        \ ( ^obj -- b )  Returns true if the ivar part of the passed-in
  2373.             \ object is identical to self.
  2374.     ^base  dup (^dlen) w@  (s=)  ;m
  2375.  
  2376.  
  2377. (*    The following methods need to be defined for all objects.
  2378.     We give them their default definitions here.
  2379. *)
  2380.  
  2381. :m CLASSINIT:  ;m    \ Our standard constructor method.  Called automatically
  2382.                     \ whenever an object is created.
  2383.  
  2384. :m DEEP_CLASSINIT:    \ Also does classinit: on all nested ivars.  Use for
  2385.                     \  totally (re-)initializing an object.
  2386.     classinit: [ self ]        \ ivsetup doesn't do this, so we do it explicitly
  2387.     (^base) -> newObject
  2388.     class: self ifa displace  0  0
  2389.     ivSetup
  2390. ;m
  2391.  
  2392.  
  2393. (*    RELEASE: is our standard destructor method.  Any objects that
  2394.     allocate heap storage will redefine this appropriately.
  2395.     Our rule is that an object will release ALL its    storage 
  2396.     when it gets a release: message. Other methods can be 
  2397.     provided to partly release storage, as needed.
  2398. *)
  2399.  
  2400. :m RELEASE:    inline{ }  ;m
  2401.  
  2402.  
  2403. (*    SEND: and BRING: handle serialization of an object, so
  2404.     it can be saved to a file or whatever.  We take a
  2405.     passed-in object as the source/sink for the serialized
  2406.     bytes.  It can be any object that supports the stream 
  2407.     methods read: and write:.
  2408.  
  2409.     Here in class Object we just assume we can just write
  2410.     the object's local data.  Any classes that use handles 
  2411.     etc. will have to do a bit more than this.
  2412.     
  2413.     We write the non-indexed and indexed data separately, 
  2414.     to meke these operations less sensitive to platform-related
  2415.     alignment questions.  On the PPC the indexed area
  2416.     starts out 4-byte aligned, but only 2-byte aligned
  2417.     on the 68k.  Of course alignment issues within the
  2418.     local ivars might rule out cross-platform compatibility
  2419.     anyway, but there will be many situations in which
  2420.     what we do here will work.
  2421. *)
  2422.  
  2423. :m SEND:  { stream \ ^dlen xwid -- }
  2424.  
  2425.     ^base (^dlen)  -> ^dlen
  2426.     ^base
  2427.     ^dlen w@                        \ ivar len
  2428.     write: [ stream ]  OK?            \ write out ivar data
  2429.  
  2430.     ^dlen 2+ w@  dup -> xwid  0EXIT    \ if not indexed, we're done
  2431.     
  2432.     idxBase dup
  2433.     4- @ 1+  xwid *                 \ indexed length
  2434.     write: [ stream ]  OK?            \ write out indexed data
  2435. ;m
  2436.  
  2437. :m BRING:  { stream \ ^dlen xwid -- }
  2438.     ^base (^dlen)  -> ^dlen
  2439.     ^base
  2440.     ^dlen w@                        \ ivar len
  2441.     read: [ stream ]  OK?            \ read ivar data
  2442.  
  2443.     ^dlen 2+ w@  dup -> xwid  0EXIT    \ if not indexed, we're done
  2444.     
  2445.     idxBase dup
  2446.     4- @ 1+  xwid *                 \ indexed length
  2447.     read: [ stream ]  OK?            \ read indexed data
  2448. ;m
  2449.  
  2450.  
  2451. :m DUMP:
  2452.     .id: self  ."  class: "  .class: self
  2453.     ^base objlen  dump  ;m
  2454.  
  2455.  
  2456. :m PRINT:        \ Used for a formatted display, if appropriate.
  2457.                 \ Default is just a dump.
  2458.     dump: self  ;m
  2459.  
  2460.  
  2461. ;class
  2462.  
  2463.  
  2464. (* ***********
  2465.  
  2466. \ A simple test of the basic class stuff - run if the plot
  2467. \  gets totally lost:
  2468.  
  2469.  
  2470. :class testClass super{ object }
  2471. :m aa: 1 2 3 ;m
  2472. :m bb: 99 aa: self  ;m
  2473. ;class
  2474.  
  2475.  
  2476. :class cl2 super{ testClass }
  2477.   testClass bloggs
  2478. :m cc:  $ 1234  bb: bloggs
  2479. ;m
  2480. ;class
  2481.  
  2482.  
  2483. cl2  myObj
  2484.  
  2485. ********** *)
  2486.  
  2487.  
  2488. \            ========= Object pointers ==========
  2489.  
  2490. \ Here we just need the PPC native version of (toOP).
  2491.  
  2492.  
  2493. true    value    check_OP_stores?    \ allows us to turn off type checking
  2494.                                     \  for stores to objPtrs
  2495.  
  2496. : (toOP)  { ^obj addr \ OPclass -- }
  2497.     \ addr is the obj ptr info in the data area, courtesy of litAddr_h
  2498.     \ (if compiling) or >body (if interpreting).  See ToObjPtr in
  2499.     \  zClass.
  2500.  
  2501.     ^obj  nilP =                \ If we're storing nil, anything goes
  2502.     check_OP_stores? not or        \ Or if checking is turned off
  2503.     NIF    
  2504.         addr 4+ @abs -> OPclass
  2505.         ^obj 8 - @abs OPclass  <>
  2506.         IF                          \ Mismatch. We give some useful(?) info.
  2507.             cr  ^obj obj> .id
  2508.             87 die
  2509.         THEN
  2510.     THEN
  2511.     ^obj addr !  ;
  2512.  
  2513.  
  2514. endload
  2515.  
  2516. +echox
  2517.  
  2518. \ ===============================================================
  2519. \                        TORTURE TESTS
  2520. \ ===============================================================
  2521.  
  2522. \ This is a slightly cut-back version of the full torture tests
  2523. \  as in zClass.  A few things aren't implemented in the target
  2524. \  compilation since the code generator doesn't use them.
  2525.  
  2526.  
  2527. : ?CHK
  2528.     2dup <>
  2529.     IF    cr .h cr .h
  2530.         true abort" check FAILED!!!"        \ error if something doesn't
  2531.                                             \  give what we expect
  2532.     ELSE
  2533.         2drop
  2534.     THEN
  2535. ;
  2536.  
  2537. : leaf  ;
  2538.  
  2539. :class    VAR    super{ object }
  2540.  
  2541.     4 bytes data
  2542.  
  2543. :m CLEAR:
  2544.     inline{ 0 ^base !}  ;m
  2545.  
  2546. :m GET:
  2547.     inline{ ^base @}  ;m
  2548.  
  2549. :m PUT:
  2550.     inline{ ^base !}  ;m
  2551.  
  2552. :m GETT:    ^base @  ;m
  2553.     
  2554. :m PUTT:    ^base !  ;m
  2555.  
  2556. :m +:
  2557.     inline{ ^base +!}  ;m
  2558.  
  2559. :m -:
  2560.     inline{ ^base -!}  ;m
  2561.  
  2562. :m ->:
  2563.     inline{ @ ^base !}  ;m
  2564.  
  2565. :m TEST:  @ ^base !  ;m
  2566.  
  2567. mlocal LOCTEST:  { aa \ bb cc -- }
  2568.  
  2569. :m AAA:    aa -> bb ;m
  2570.  
  2571. :mloc  LOCTEST:
  2572.     aaa: self aaa: self aaa: self cc -> bb  ;mloc
  2573.  
  2574.  
  2575. :m PRINT:
  2576.     ^base @  .  ;m
  2577.  
  2578. :m CLASSINIT:
  2579.     $ 123  put: self  ;m
  2580.  
  2581. ;class
  2582.  
  2583.  
  2584. :class    BYTE    super{ object }
  2585.  
  2586.     1 bytes data
  2587.  
  2588. :m CLEAR:
  2589.     inline{ 0 ^base c!}  ;m
  2590.  
  2591. :m GET:
  2592.     inline{ ^base c@x}  ;m
  2593.  
  2594. :m UGET:
  2595.     inline{ ^base c@}  ;m
  2596.  
  2597. :m PUT:
  2598.     inline{ ^base c!}  ;m
  2599.  
  2600. :m ->:
  2601.     inline{ c@ ^base c!}  ;m
  2602.  
  2603. :m PRINT:
  2604.     ^base c@  .        ;m
  2605.  
  2606. :m CLASSINIT:    9 put: self  ;m
  2607.  
  2608. ;class
  2609.  
  2610. \ +echox
  2611.  
  2612. \ some very simple testing, to start with:
  2613.  
  2614. 0        value    testVal
  2615.         var        aVar
  2616.         byte    aByte
  2617.  
  2618. : test1
  2619. ." test1" cr
  2620.     987 avar !  get: avar  987 ?chk            \ optimizes
  2621.     addr: avar  -> testVal
  2622.     876 testVal !                            \ should clobber opt
  2623.     get: avar  876  ?chk
  2624. ;
  2625.  
  2626. : test2            \ testing late binding - assumes test1 done
  2627. ." test2" cr
  2628.     get: [ avar ]  876  ?chk
  2629. ;
  2630.  
  2631.  
  2632. var vv
  2633.  
  2634.  
  2635. :class    BOOL    super{ byte }
  2636.  
  2637. :m GET:
  2638.     inline{ ^base c@x}  ;m
  2639.  
  2640. :m PUT:
  2641.     inline{ 0<> ^base c!}  ;m
  2642.  
  2643. :m SET:
  2644.     inline{ true ^base c!}  ;m
  2645.  
  2646. :m PRINT:
  2647.     get: self  IF  ." true"  ELSE  ." false"  THEN  ;m
  2648.  
  2649. :m CLASSINIT:    clear: self  ;m
  2650.  
  2651. ;class
  2652.  
  2653.  
  2654. :class    BARRAY  super{ object }  1 indexed
  2655.  
  2656. :m  AT:        \ ( index -- n )
  2657.     inline{ ^elem c@}  ;m
  2658.  
  2659. :m  TO:        \ ( n index -- )
  2660.     inline{ ^elem c!}  ;m
  2661.  
  2662.  
  2663. :m ^ELEM:    \ ( index -- addr )
  2664.     inline{ ^elem}  ;m
  2665.  
  2666. :m FILL:    \ ( value -- )  Fills all elements with value.
  2667.     idxbase  limit 2*  bounds
  2668.     ?DO  dup  i c!  LOOP  drop  ;m
  2669.  
  2670. :m WIDTH:    1  ;m        \ Faster than the default in Object
  2671.  
  2672. :m GETELEM:    \ ( addr -- n )  Fetches one element at addr
  2673.     c@x  ;m
  2674.  
  2675. :m TEST:    at: self  ;m
  2676.  
  2677. ;class
  2678.  
  2679.  
  2680. \ Testing arrays:
  2681.  
  2682. 20 barray bb
  2683.  
  2684. : test3
  2685. ." test3" cr
  2686.     $ 9887 bb 20 + c!
  2687.     12 -> testVal
  2688.     testVal test: bb  $ 87 ?chk
  2689.     120 -> testVal
  2690. \ ." should fail range check and trap - just step past the tw:" cr cr
  2691. \    testVal test: bb            \ should fail range check
  2692. ;
  2693.  
  2694. \ also we test indexed classes which are subclassed and have
  2695. \  added ivars, to make sure we get the right offset to the
  2696. \  indexed header:
  2697.  
  2698. :class    INDEXED-OBJ  super{ object }
  2699.  
  2700. :m ^ELEM:    ^elem  ;m
  2701.  
  2702. :m LIMIT:    limit  ;m
  2703.  
  2704. :m WIDTH:    idxbase  6 -  w@  ;m
  2705.  
  2706. :m IXADDR:    idxbase  ;m
  2707.  
  2708. :m CLEARX:    \ Erases indexed area.
  2709.     idxbase  limit  width: self  *  erase  ;m
  2710.  
  2711. :m CLASSINIT:    clearX: self  ;m
  2712.  
  2713. ;class
  2714.  
  2715.  
  2716. :class    WARRAY  super{ indexed-obj }  2 indexed
  2717.  
  2718. :m AT:        \ ( index -- n )
  2719.     inline{ ^elem w@x}  ;m
  2720.     
  2721. :m ATT:        ^elem w@x  ;m
  2722.  
  2723. :m TO:        \ ( n index -- )
  2724.     inline{ ^elem w!}  ;m
  2725.  
  2726. ;class
  2727.  
  2728.  
  2729. :class  TRIGTABLE    super{ wArray }
  2730.  
  2731.     3    wArray  AXISVALS
  2732. ;class
  2733.  
  2734. 10 trigtable ttt
  2735. $ 56  ttt $ 26 + w!
  2736.  
  2737. : test4 { \ xx -- }
  2738.     ." test4" cr
  2739.     addr: ttt  -> xx        \ so we can look at it in the debugger
  2740.     3 at: ttt  $ 56 ?chk  ;
  2741.  
  2742.  
  2743. \ Testing object pointers
  2744.  
  2745. var        vv1
  2746.  
  2747. objPtr    ov    class_is var
  2748. objPtr    ov1    class_is var
  2749.  
  2750. objPtr    ob    class_is bool
  2751.  
  2752.  
  2753. : test5
  2754.     ." test5" cr
  2755.     $ 765 put: vv  $ 543 put: vv1
  2756.     vv1 -> ov1  vv -> ov
  2757.     gett: ov1  $ 543  ?chk  get: ov  $ 765 ?chk
  2758.     $ 345 putt: ov  get: ov  $ 345 ?chk  ;
  2759.  
  2760.  
  2761.  
  2762. \ static ivar check omitted - not needed for code generator so not
  2763. \  implemented in target compilation
  2764.  
  2765.  
  2766.  
  2767. \ Testing late bind to self
  2768.  
  2769. :class VAR+ super{ var }
  2770.  
  2771. :m QQ:    get: [self]        \ should make class general
  2772.         get: [ self ]    \ shouldn't give any error
  2773. ;m
  2774.  
  2775. ;class
  2776.  
  2777. var+ VVV
  2778.  
  2779. \ qq: vvv        \ no need for ?chk since it will give its own error
  2780.  
  2781. : test8
  2782.     ." test8" cr
  2783.     qq: vvv  2drop
  2784. ;
  2785.  
  2786.  
  2787. \ Testing records and unions.  Also, the TEST: method piles up so many
  2788. \  values that this also tests register spilling with a duplicate value!
  2789.  
  2790. :class RECTEST super{ object }
  2791.     var    vv
  2792.     record RR
  2793.     {        var        v1
  2794.             bool    b1
  2795.         3    barray  bbb
  2796.             byte    b3            \ now aligned - unions should normally
  2797.                                 \  start out aligned, but we don't insist
  2798.                                 \  on it
  2799.         union {    byte    b2
  2800.                 var        v2
  2801.                 record    {    byte bb1
  2802.                             byte bb2    }
  2803.             }
  2804.             var        v3
  2805.     }
  2806.     
  2807. :m TEST:
  2808.     4 0 to: bbb  5 1 to: bbb  6 2 to: bbb
  2809.     $ 33  put: vv
  2810.     $ 123 put: v1  set: b1  $ 124 put: v2  7 put: b3
  2811.     $ 35 put: bb1  $ 36 put: bb2  $ 125 put: v3  $ 37 put: b2
  2812.     get: v1  put: b1
  2813.     get: b2  get: v2  get: bb1  get: bb2  get: v3
  2814.     addr: rr  36 + @
  2815. ;m
  2816. ;class
  2817.  
  2818. recTest rrr
  2819.  
  2820. : test9
  2821.     ." test9" cr
  2822.     $ 33  addr: vvv !
  2823.     qq: vvv
  2824.     $ 33        ?chk
  2825.     $ 33        ?chk
  2826.     test: rrr
  2827.     $ 125        ?chk
  2828.     $ 125        ?chk
  2829.     $ 36        ?chk
  2830.     $ 37        ?chk
  2831.     $ 37360124    ?chk
  2832.     $ 37        ?chk
  2833.     rrr $ 2C + @  $ 04050607  ?chk
  2834. ;
  2835.  
  2836.  
  2837. \ testing multiple inheritance
  2838.  
  2839. :class INT  super{ object }
  2840.  
  2841.     2    bytes    data
  2842.  
  2843. :m CLEAR:
  2844.     inline{ 0 ^base ! }  ;m
  2845.  
  2846. :m UGET:
  2847.     inline{ ^base w@ }  ;m
  2848.  
  2849. :m GET:
  2850.     inline{ ^base w@x }  ;m
  2851.  
  2852. :m PUT:
  2853.     inline{ obj w! }  ;m
  2854.  
  2855. :m PUTT:    ^base w!  ;m
  2856. :m IPUT:    ^base w!  ;m        \ used in testing mult inheritance
  2857.  
  2858. :m CLASSINIT:  $ 456 put: self  ;m
  2859.  
  2860. ;class
  2861.  
  2862.  
  2863. :class CC  super{ byte int var bool }
  2864.  
  2865. :m TEST:
  2866. iput: self    \ check it compiles
  2867.     uget: self            \ offs should be 0
  2868.     +: self                \ offs should be 4
  2869.     set: self  ;m        \ offs should be E
  2870.  
  2871. :m TEST1:
  2872.     set: self
  2873.     get: super> bool    \ should get -1
  2874.     get: super
  2875. ;m
  2876.     
  2877. :m setValues:
  2878.     9 put: super> byte
  2879.     $ 456  putt: super        \ should go to the int
  2880.     $ 456  put: super> int
  2881.     $ 123  put: super> var
  2882.     set: super
  2883. ;m
  2884.  
  2885. ;class
  2886.  
  2887. cc myCC
  2888.  
  2889. : test10 { \ addr -- }
  2890.     ." test10" cr
  2891.     addr: mycc -> addr
  2892.     setValues: mycc
  2893.     mycc @        $ 09000000    ?chk
  2894.     mycc 4+   @    $ fff40002  ?chk
  2895.     mycc 8 +  @    $ 04560000    ?chk
  2896.     mycc 12 + @ $ ffec0002  ?chk
  2897.     mycc 16 + @    $ 123        ?chk
  2898.     mycc 20 + @ $ ffe40002  ?chk
  2899.     mycc 24 + @ $ ff000000  ?chk
  2900. ;
  2901.  
  2902.  
  2903. :class STRANGE  super{ object }
  2904.     var VV
  2905.     byte BB
  2906. :m GET:  get: vv  get: bb  ;m
  2907. :m PUT:  put: bb  put: vv  ;m
  2908.  
  2909. ;class
  2910.  
  2911.  
  2912. :class    ARRAY  super{ indexed-obj }  4 indexed
  2913.  
  2914. :m AT:        \ ( index -- n )
  2915.     inline{ ^elem @}  ;m
  2916.     
  2917. :m ATT:        ^elem @  ;m
  2918.  
  2919. :m TO:        \ ( n index -- )
  2920.     inline{ ^elem !}  ;m
  2921.  
  2922. :m  +TO:        \ ( n index -- )
  2923.     inline{ ^elem +!}  ;m
  2924.  
  2925. :m -TO:        \ ( n index -- )
  2926.     inline{ ^elem -!}  ;m
  2927.  
  2928. :m FILL:        \ ( value -- )  Fills all elements with value.
  2929.     idxbase  limit 4*  bounds
  2930.     DO  dup  i !  4 +LOOP  drop  ;m
  2931.  
  2932.  
  2933. :m ATEST:
  2934.     1 at: self  ;m
  2935.  
  2936. ;class
  2937.  
  2938.  
  2939. :class MULT    super{ var int array }
  2940.  
  2941. :m MTEST:    $ 456  put: super> int  $ 123  put: super> var
  2942.             uget: super  999 1 to: self  ;m
  2943.             
  2944. :m MAT:        at: self  ;m
  2945.  
  2946. ;class
  2947.  
  2948.  
  2949. objPtr    OO    class_is mult
  2950. objPtr    OOO    class_is int
  2951.  
  2952. :class IVXX    super{ object }
  2953.     10 bytes data2
  2954.     int    i1
  2955.     int    i2
  2956.     130 bytes qqqq        \ Include to check >128 distance
  2957.                         \  index addressing of array qwert
  2958.     9 array qwert
  2959.  
  2960. :m ITEST:
  2961.     $ 8456 dup  i1 w!  addr: i2 w!        \ should be equivalent
  2962.     get: i1  uget: i2  66 put: i2
  2963.     99 3 to: qwert  1234 drop  3 at: qwert
  2964.     addr: i2  -> ooo  ;m
  2965.  
  2966. :m GETQWERT:
  2967.     addr: qwert  ;m
  2968. ;class
  2969.  
  2970. int ii
  2971. 3 mult    mm
  2972. ivxx    iv
  2973.  
  2974. : test11
  2975.     ." test11" cr
  2976.     itest: iv
  2977.     $ 63    ?chk
  2978.     $ 8456    ?chk
  2979.     $ ffff8456    ?chk
  2980.     mtest: mm
  2981.     $ 456    ?chk
  2982.     88 iput: mm        \ Note: get: mm will bind to the var, but uget: mm
  2983.                     \ will bind to the int and give 88.
  2984.  
  2985.     get: mm  $ 123    ?chk
  2986.     uget: mm 88        ?chk
  2987. ;
  2988.  
  2989.  
  2990. : test12
  2991. ." test12" cr
  2992.     itest: iv
  2993.     getqwert: iv  3 swap at: **        99    ?chk
  2994.     mtest: mm            $ 456    ?chk
  2995.     1 at: mm            999 ?chk
  2996.     1 mat: mm            999 ?chk
  2997.     1 mm at: mult        999 ?chk
  2998.     1 mm at: []            999 ?chk
  2999.     mm -> oo
  3000.     1 at: oo            999     ?chk
  3001.     1 mat: oo            999     ?chk
  3002.     uget: mm            $ 456    ?chk
  3003.     addr: mm  addr: oo            ?chk  \ Both numbers shd be same
  3004.     uget: ooo            66        ?chk
  3005. ;
  3006.  
  3007.  
  3008. \ testing ivSetup (via deep_classinit: ) - this should put the $123 and
  3009. \  $456 in the var and the int, and store the same offsets in the header
  3010. \  that are already there.
  3011.  
  3012. :class ivsTestClass  super{ var int array }
  3013.     record
  3014.     {    var        v1
  3015.         int        i1
  3016.         byte    b1
  3017.      3     array    a1
  3018.     }
  3019. ;class
  3020.  
  3021. 5 ivsTestClass  ivs1
  3022.  
  3023. : test13
  3024. ." test13" cr
  3025.     deep_classinit: ivs1
  3026.     addr: ivs1 @        $ 123          ?chk
  3027.     addr: ivs1 4 + @    $ FFF4003A    ?chk
  3028.     addr: ivs1 8 + @    $ 04560000    ?chk
  3029.     addr: ivs1 12 + @    $ FFEC0032    ?chk
  3030.     addr: ivs1 16 + @    $ 123        ?chk
  3031.     addr: ivs1 20 + @    $ 04560900    ?chk
  3032.     addr: ivs1 24 + @    $ 0            ?chk    \ array has no name so zero here
  3033.     addr: ivs1 28 + c@    $ 08        ?chk    \ rest of reloc addr can change
  3034.     addr: ivs1 32 + @    $ FFFC000A    ?chk
  3035.     addr: ivs1 36 + @    $ 4            ?chk
  3036.      addr: ivs1 40 + @    $ 2            ?chk
  3037.  ;
  3038.  
  3039.  
  3040. \ Temp object check omitted - not needed for code generator so not
  3041. \  implemented in target compilation
  3042.  
  3043.  
  3044.  
  3045. \ =========== TORTURE runs the test! ============
  3046.  
  3047. : TORTURE
  3048.     ." torture tests start..." cr cr
  3049.     test1 test2 test3 test4 test5
  3050.     test8 test9
  3051.     test10 test11 test12 test13
  3052.     cr cr ." torture tests WORKED!!!" cr
  3053. ;
  3054.  
  3055.  
  3056.  
  3057.  
  3058. \ =========== the current test block ============
  3059.  
  3060.  
  3061. :f run
  3062.     cr cr ." Hi there." cr
  3063.     ." Type a number to start the tests." cr  1 2 3
  3064.     
  3065.     begin
  3066.         query cr
  3067.         begin
  3068.             rest nip 0>
  3069.         while
  3070.             defined?
  3071.             if        execute
  3072.             else
  3073.                     number
  3074.                     torture
  3075.             then
  3076.         repeat
  3077.         .s cr
  3078.     again
  3079. ;f
  3080.  
  3081. :f quit  run  ;f        \ temp so we can catch errors!
  3082.  
  3083. \ marker m__pStruct
  3084. \ endload
  3085.  
  3086. \ ================ end of test block =================
  3087.